1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package calfeed
import (
"strings"
"testing"
"time"
)
func TestICalEscapeInjection(t *testing.T) {
// A malicious custom-calendar name must not be able to inject lines/props.
got := icalEscape("Evil\r\nBEGIN:VEVENT\nSUMMARY:hijack; a,b\\c")
if strings.ContainsAny(got, "\r\n") {
t.Fatalf("unescaped newline survived: %q", got)
}
for _, sub := range []string{`\n`, `\;`, `\,`, `\\`} {
if !strings.Contains(got, sub) {
t.Fatalf("missing escape %q in %q", sub, got)
}
}
}
func TestICalStructure(t *testing.T) {
days := []DayView{{
Date: "2026-01-06", Season: "time-after-epiphany", Week: 1, Colour: "white",
Observed: CelView{Name: "The Epiphany of the Lord", Rank: "class-1"},
Readings: []ReadingView{{Part: "gospel", Citation: "Matt 2:1-12"}},
}}
out := string(ICal("old", days, time.Date(2026, 7, 27, 12, 0, 0, 0, time.UTC)))
for _, want := range []string{
"BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//lectio//calendar//EN",
"BEGIN:VEVENT", "UID:2026-01-06-old@lectio", "DTSTART;VALUE=DATE:20260106",
"DTEND;VALUE=DATE:20260107", "SUMMARY:The Epiphany of the Lord",
"CATEGORIES:WHITE", "DTSTAMP:20260727T120000Z", "END:VEVENT", "END:VCALENDAR",
} {
if !strings.Contains(out, want) {
t.Fatalf("missing %q in:\n%s", want, out)
}
}
// injection attempt via day count: exactly one VEVENT
if strings.Count(out, "BEGIN:VEVENT") != 1 {
t.Fatalf("expected 1 VEVENT")
}
}
func TestFoldLine(t *testing.T) {
long := "SUMMARY:" + strings.Repeat("x", 200)
for _, line := range strings.Split(foldLine(long), "\r\n") {
if len(line) > 75 {
t.Fatalf("line exceeds 75 octets: %d", len(line))
}
}
}
|