rss email digests over ssh because you're a cool kid
herald.dunkirk.sh
go
rss
rss-reader
ssh
charm
1package config
2
3import (
4 "testing"
5)
6
7func TestParse_Empty(t *testing.T) {
8 cfg, err := Parse("")
9 if err != nil {
10 t.Fatalf("Parse(\"\") failed: %v", err)
11 }
12 if cfg == nil {
13 t.Fatal("expected non-nil config")
14 }
15 if !cfg.Digest {
16 t.Error("expected Digest default to be true")
17 }
18 if cfg.Inline {
19 t.Error("expected Inline default to be false")
20 }
21 if len(cfg.Feeds) != 0 {
22 t.Errorf("expected 0 feeds, got %d", len(cfg.Feeds))
23 }
24}
25
26func TestParse_Comments(t *testing.T) {
27 input := `
28# This is a comment
29# Another comment
30
31=: email test@example.com
32`
33 cfg, err := Parse(input)
34 if err != nil {
35 t.Fatalf("Parse failed: %v", err)
36 }
37 if cfg.Email != "test@example.com" {
38 t.Errorf("expected email test@example.com, got %s", cfg.Email)
39 }
40}
41
42func TestParse_EmailDirective(t *testing.T) {
43 input := "=: email user@example.com"
44 cfg, err := Parse(input)
45 if err != nil {
46 t.Fatalf("Parse failed: %v", err)
47 }
48 if cfg.Email != "user@example.com" {
49 t.Errorf("expected email user@example.com, got %s", cfg.Email)
50 }
51}
52
53func TestParse_CronDirective(t *testing.T) {
54 input := "=: cron 0 8 * * *"
55 cfg, err := Parse(input)
56 if err != nil {
57 t.Fatalf("Parse failed: %v", err)
58 }
59 if cfg.CronExpr != "0 8 * * *" {
60 t.Errorf("expected cron '0 8 * * *', got %s", cfg.CronExpr)
61 }
62}
63
64func TestParse_DigestDirective(t *testing.T) {
65 tests := []struct {
66 input string
67 expected bool
68 }{
69 {"=: digest true", true},
70 {"=: digest false", false},
71 {"=: digest 1", true},
72 {"=: digest 0", false},
73 {"=: digest invalid", true}, // default
74 }
75
76 for _, tt := range tests {
77 cfg, err := Parse(tt.input)
78 if err != nil {
79 t.Fatalf("Parse(%q) failed: %v", tt.input, err)
80 }
81 if cfg.Digest != tt.expected {
82 t.Errorf("Parse(%q): expected Digest=%v, got %v", tt.input, tt.expected, cfg.Digest)
83 }
84 }
85}
86
87func TestParse_InlineDirective(t *testing.T) {
88 tests := []struct {
89 input string
90 expected bool
91 }{
92 {"=: inline true", true},
93 {"=: inline false", false},
94 {"=: inline 1", true},
95 {"=: inline 0", false},
96 {"=: inline invalid", false}, // default
97 }
98
99 for _, tt := range tests {
100 cfg, err := Parse(tt.input)
101 if err != nil {
102 t.Fatalf("Parse(%q) failed: %v", tt.input, err)
103 }
104 if cfg.Inline != tt.expected {
105 t.Errorf("Parse(%q): expected Inline=%v, got %v", tt.input, tt.expected, cfg.Inline)
106 }
107 }
108}
109
110func TestParse_FeedWithoutName(t *testing.T) {
111 input := "=> https://example.com/feed.xml"
112 cfg, err := Parse(input)
113 if err != nil {
114 t.Fatalf("Parse failed: %v", err)
115 }
116 if len(cfg.Feeds) != 1 {
117 t.Fatalf("expected 1 feed, got %d", len(cfg.Feeds))
118 }
119 if cfg.Feeds[0].URL != "https://example.com/feed.xml" {
120 t.Errorf("expected URL https://example.com/feed.xml, got %s", cfg.Feeds[0].URL)
121 }
122 if cfg.Feeds[0].Name != "" {
123 t.Errorf("expected empty name, got %s", cfg.Feeds[0].Name)
124 }
125}
126
127func TestParse_FeedWithName(t *testing.T) {
128 input := `=> https://example.com/feed.xml "Example Feed"`
129 cfg, err := Parse(input)
130 if err != nil {
131 t.Fatalf("Parse failed: %v", err)
132 }
133 if len(cfg.Feeds) != 1 {
134 t.Fatalf("expected 1 feed, got %d", len(cfg.Feeds))
135 }
136 if cfg.Feeds[0].URL != "https://example.com/feed.xml" {
137 t.Errorf("expected URL https://example.com/feed.xml, got %s", cfg.Feeds[0].URL)
138 }
139 if cfg.Feeds[0].Name != "Example Feed" {
140 t.Errorf("expected name 'Example Feed', got %s", cfg.Feeds[0].Name)
141 }
142}
143
144func TestParse_MultipleFeeds(t *testing.T) {
145 input := `
146=> https://feed1.com/rss
147=> https://feed2.com/atom "Feed Two"
148=> https://feed3.com/json "Feed Three"
149`
150 cfg, err := Parse(input)
151 if err != nil {
152 t.Fatalf("Parse failed: %v", err)
153 }
154 if len(cfg.Feeds) != 3 {
155 t.Fatalf("expected 3 feeds, got %d", len(cfg.Feeds))
156 }
157
158 if cfg.Feeds[0].URL != "https://feed1.com/rss" {
159 t.Errorf("feed[0] URL wrong: %s", cfg.Feeds[0].URL)
160 }
161 if cfg.Feeds[0].Name != "" {
162 t.Errorf("feed[0] should have empty name, got %s", cfg.Feeds[0].Name)
163 }
164
165 if cfg.Feeds[1].URL != "https://feed2.com/atom" {
166 t.Errorf("feed[1] URL wrong: %s", cfg.Feeds[1].URL)
167 }
168 if cfg.Feeds[1].Name != "Feed Two" {
169 t.Errorf("feed[1] name wrong: %s", cfg.Feeds[1].Name)
170 }
171
172 if cfg.Feeds[2].Name != "Feed Three" {
173 t.Errorf("feed[2] name wrong: %s", cfg.Feeds[2].Name)
174 }
175}
176
177func TestParse_CompleteConfig(t *testing.T) {
178 input := `
179# My feed configuration
180=: email user@example.com
181=: cron 0 9 * * *
182=: digest true
183=: inline false
184
185=> https://blog.example.com/feed.xml "Example Blog"
186=> https://news.example.com/rss
187`
188 cfg, err := Parse(input)
189 if err != nil {
190 t.Fatalf("Parse failed: %v", err)
191 }
192
193 if cfg.Email != "user@example.com" {
194 t.Errorf("email wrong: %s", cfg.Email)
195 }
196 if cfg.CronExpr != "0 9 * * *" {
197 t.Errorf("cron wrong: %s", cfg.CronExpr)
198 }
199 if !cfg.Digest {
200 t.Error("digest should be true")
201 }
202 if cfg.Inline {
203 t.Error("inline should be false")
204 }
205 if len(cfg.Feeds) != 2 {
206 t.Fatalf("expected 2 feeds, got %d", len(cfg.Feeds))
207 }
208}
209
210func TestParse_CaseInsensitiveDirectives(t *testing.T) {
211 input := `
212=: EMAIL test@example.com
213=: CRON 0 8 * * *
214=: DIGEST false
215=: INLINE true
216`
217 cfg, err := Parse(input)
218 if err != nil {
219 t.Fatalf("Parse failed: %v", err)
220 }
221 if cfg.Email != "test@example.com" {
222 t.Error("EMAIL directive not parsed")
223 }
224 if cfg.CronExpr != "0 8 * * *" {
225 t.Error("CRON directive not parsed")
226 }
227 if cfg.Digest {
228 t.Error("DIGEST directive not parsed")
229 }
230 if !cfg.Inline {
231 t.Error("INLINE directive not parsed")
232 }
233}
234
235func TestParseBool(t *testing.T) {
236 tests := []struct {
237 input string
238 defaultVal bool
239 expected bool
240 }{
241 {"true", false, true},
242 {"false", true, false},
243 {"1", false, true},
244 {"0", true, false},
245 {"yes", false, false}, // invalid, returns default
246 {"no", true, true}, // invalid, returns default
247 {"", false, false}, // invalid, returns default
248 {"invalid", true, true}, // invalid, returns default
249 }
250
251 for _, tt := range tests {
252 result := parseBool(tt.input, tt.defaultVal)
253 if result != tt.expected {
254 t.Errorf("parseBool(%q, %v) = %v, expected %v", tt.input, tt.defaultVal, result, tt.expected)
255 }
256 }
257}