all repos

rss-tools @ 11fd04d4db9db13f1178670ca3f0f008409951bc

get rss feed from sources that(i need and) dont provide one

rss-tools/app/atom_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
fix moviefeed, 28 days ago
1
package app
2
3
import (
4
	"bytes"
5
	"encoding/xml"
6
	"net/http"
7
	"net/http/httptest"
8
	"strings"
9
	"testing"
10
	"time"
11
12
	"olexsmir.xyz/x/is"
13
)
14
15
func TestFeedBuilderAddEntryDefaults(t *testing.T) {
16
	feed := NewFeed("test", "feed-id")
17
	feed.Add(FeedEntry{Title: "entry", Content: "body"})
18
19
	is.Equal(t, 1, len(feed.f.Entries))
20
	entry := feed.f.Entries[0]
21
	is.NotEqual(t, "", entry.ID)
22
	is.NotEqual(t, "", entry.Updated)
23
	is.Equal(t, 1, len(feed.f.Authors))
24
	is.Equal(t, "rss-tools", feed.f.Authors[0].Name)
25
}
26
27
func TestFeedBuilderBytesAndWriteTo(t *testing.T) {
28
	updated := time.Date(2026, 4, 20, 12, 30, 0, 0, time.UTC)
29
	feed := NewFeed("test", "feed-id").
30
		WithSubtitle("subtitle").
31
		Add(FeedEntry{Title: "entry", Content: "content", Updated: updated})
32
33
	raw, err := feed.Bytes()
34
	is.Err(t, err, nil)
35
	if !bytes.Contains(raw, []byte("<subtitle>subtitle</subtitle>")) {
36
		t.Fatalf("expected subtitle in serialized feed")
37
	}
38
39
	var parsed AtomFeed
40
	is.Err(t, xml.Unmarshal(raw, &parsed), nil)
41
	is.Equal(t, "test", parsed.Title)
42
}
43
44
func TestFeedBuilderWithAuthor(t *testing.T) {
45
	feed := NewFeed("test", "feed-id").WithAuthor("moviefeed")
46
	raw, err := feed.Bytes()
47
	is.Err(t, err, nil)
48
	var parsed AtomFeed
49
	is.Err(t, xml.Unmarshal(raw, &parsed), nil)
50
	is.Equal(t, 1, len(parsed.Authors))
51
	is.Equal(t, "moviefeed", parsed.Authors[0].Name)
52
}
53
54
func TestFeedBuilderRender(t *testing.T) {
55
	r := httptest.NewRecorder()
56
	err := NewFeed("test", "feed-id").
57
		Add(FeedEntry{
58
			Title:   "entry",
59
			ID:      "entry-id",
60
			Content: "content",
61
			Updated: time.Date(2026, 4, 20, 8, 0, 0, 0, time.UTC),
62
		}).
63
		Render(r)
64
	is.Err(t, err, nil)
65
66
	is.Equal(t, http.StatusOK, r.Code)
67
	if got := r.Header().Get("Content-Type"); !strings.Contains(got, "application/atom+xml") {
68
		t.Fatalf("unexpected content type: %q", got)
69
	}
70
}
71
72
func TestFeedEntryTextContent(t *testing.T) {
73
	feed := NewFeed("test", "feed-id").
74
		Add(FeedEntry{
75
			Title:       "text entry",
76
			Content:     "plain text content",
77
			ContentType: "text",
78
			Updated:     time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
79
		})
80
81
	raw, err := feed.Bytes()
82
	is.Err(t, err, nil)
83
	if !strings.Contains(string(raw), `<content type="text">plain text content</content>`) {
84
		t.Fatalf("expected text content with type attribute in serialized feed")
85
	}
86
87
	var parsed AtomFeed
88
	is.Err(t, xml.Unmarshal(raw, &parsed), nil)
89
	is.Equal(t, 1, len(parsed.Entries))
90
91
	entry := parsed.Entries[0]
92
	is.Equal(t, "text", entry.Content.Type)
93
	is.Equal(t, "plain text content", entry.Content.Value)
94
}
95
96
func TestFeedEntryHtmlContent(t *testing.T) {
97
	htmlContent := "<p>Hello <strong>World</strong></p>"
98
	feed := NewFeed("test", "feed-id").
99
		Add(FeedEntry{
100
			Title:       "html entry",
101
			Content:     htmlContent,
102
			ContentType: "html",
103
			Updated:     time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
104
		})
105
106
	raw, err := feed.Bytes()
107
	is.Err(t, err, nil)
108
	if !strings.Contains(string(raw), `<content type="html">`) {
109
		t.Fatalf("expected HTML content with type='html' attribute in serialized feed")
110
	}
111
112
	var parsed AtomFeed
113
	is.Err(t, xml.Unmarshal(raw, &parsed), nil)
114
	is.Equal(t, 1, len(parsed.Entries))
115
116
	entry := parsed.Entries[0]
117
	is.Equal(t, "html", entry.Content.Type)
118
	is.Equal(t, htmlContent, entry.Content.Value)
119
}
120
121
func TestFeedEntryXHTMLContent(t *testing.T) {
122
	xhtmlContent := `<body><p>Hello <strong>World</strong></p></body>`
123
	feed := NewFeed("test", "feed-id").
124
		Add(FeedEntry{
125
			Title:       "xhtml entry",
126
			Content:     xhtmlContent,
127
			ContentType: "xhtml",
128
			Updated:     time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
129
		})
130
131
	raw, err := feed.Bytes()
132
	is.Err(t, err, nil)
133
	if !strings.Contains(string(raw), `<content type="xhtml">`) {
134
		t.Fatalf("expected XHTML content with type='xhtml' attribute in serialized feed")
135
	}
136
	if !strings.Contains(string(raw), `<div xmlns="http://www.w3.org/1999/xhtml"><body><p>Hello <strong>World</strong></p></body></div>`) {
137
		t.Fatalf("expected XHTML div wrapper for content")
138
	}
139
}
140
141
func TestFeedEntryLinks(t *testing.T) {
142
	feed := NewFeed("test", "feed-id").
143
		Add(FeedEntry{
144
			Title:   "entry",
145
			Content: "hello",
146
			Links: []FeedLink{
147
				{Rel: "alternate", Type: "text/html", Href: "https://example.com/item"},
148
			},
149
			Updated: time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
150
		})
151
152
	raw, err := feed.Bytes()
153
	is.Err(t, err, nil)
154
	if !strings.Contains(string(raw), `<link rel="alternate" type="text/html" href="https://example.com/item"></link>`) {
155
		t.Fatalf("expected link element in serialized feed")
156
	}
157
158
	var parsed AtomFeed
159
	is.Err(t, xml.Unmarshal(raw, &parsed), nil)
160
	is.Equal(t, 1, len(parsed.Entries))
161
	is.Equal(t, 1, len(parsed.Entries[0].Links))
162
	is.Equal(t, "https://example.com/item", parsed.Entries[0].Links[0].Href)
163
}
164
165
func TestFeedEntryLinksWithLength(t *testing.T) {
166
	feed := NewFeed("test", "feed-id").
167
		Add(FeedEntry{
168
			Title:   "entry",
169
			Content: "hello",
170
			Links: []FeedLink{
171
				{Rel: "enclosure", Type: "image/jpeg", Length: "0", Href: "https://example.com/item.jpg"},
172
			},
173
			Updated: time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
174
		})
175
176
	raw, err := feed.Bytes()
177
	is.Err(t, err, nil)
178
	if !strings.Contains(string(raw), `rel="enclosure" type="image/jpeg" length="0" href="https://example.com/item.jpg"`) {
179
		t.Fatalf("expected enclosure link with length in serialized feed")
180
	}
181
}
182
183
func TestFeedMultipleEntriesWithMixedContentTypes(t *testing.T) {
184
	updated := time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC)
185
	feed := NewFeed("test", "feed-id").
186
		Add(FeedEntry{
187
			Title:       "text entry",
188
			Content:     "plain text",
189
			ContentType: "text",
190
			Updated:     updated,
191
		}).
192
		Add(FeedEntry{
193
			Title:       "html entry",
194
			Content:     "<p>html content</p>",
195
			ContentType: "html",
196
			Updated:     updated,
197
		}).
198
		Add(FeedEntry{
199
			Title:   "default entry",
200
			Content: "default content",
201
			Updated: updated,
202
		})
203
204
	raw, err := feed.Bytes()
205
	is.Err(t, err, nil)
206
207
	var parsed AtomFeed
208
	is.Err(t, xml.Unmarshal(raw, &parsed), nil)
209
	is.Equal(t, 3, len(parsed.Entries))
210
211
	tests := []struct {
212
		name         string
213
		expectedType string
214
		expectedText string
215
	}{
216
		{"text entry", "text", "plain text"},
217
		{"html entry", "html", "<p>html content</p>"},
218
		{"default entry", "text", "default content"},
219
	}
220
	for i, tc := range tests {
221
		is.Equal(t, tc.name, parsed.Entries[i].Title)
222
		is.Equal(t, tc.expectedText, parsed.Entries[i].Content.Value)
223
		is.Equal(t, tc.expectedType, parsed.Entries[i].Content.Type)
224
	}
225
}