Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/platform/icalendar/icalendar_test.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/platform/icalendar/icalendar_test.go |
| Original SHA-256 | 35cdf602b9d09d6c49006c593562b03b40f855d8b0367f267a026056c193056b |
| Git blob SHA | 0bda4254200b8503590bb3e0c5144ddfe77958d9 |
| Reading-copy SHA-256 | 35cdf602b9d09d6c49006c593562b03b40f855d8b0367f267a026056c193056b |
Recovered source transcript
Download complete source text ↓161 lines · 5.8 KB
package icalendar
import (
"strings"
"testing"
"time"
)
// unfold reverses the wrapping, which is what a calendar client does before reading a value. Asserting
// against folded text is asserting against a transport detail: RSVP=TRUE is present and correct even when it
// happens to straddle a fold.
func unfold(s string) string { return strings.ReplaceAll(s, "\r\n ", "") }
func sample() Event {
return Event{
UID: "offer-1@missionmatch",
Summary: "Interview, Network Engineer",
Description: "Client interview with Dana",
Location: "Building 4, third floor, ask for Dana",
Start: time.Date(2026, 8, 3, 14, 0, 0, 0, time.UTC),
End: time.Date(2026, 8, 3, 14, 45, 0, 0, time.UTC),
OrganizerName: "Acme Recruiting",
OrganizerEmail: "talent@acme.test",
AttendeeName: "Jordan Analyst",
AttendeeEmail: "jordan@example.test",
}
}
// An unescaped comma silently truncates the field in the recipient's calendar, so a location becomes
// "Building 4" instead of the whole thing. It is silent, which is what makes it worth a test.
func TestCommasAndSemicolonsAreEscaped(t *testing.T) {
out := unfold(Render(sample()))
if !strings.Contains(out, `Building 4\, third floor\, ask for Dana`) {
t.Errorf("the location was not escaped:\n%s", out)
}
e := sample()
e.Summary = "A; B, C \\ D"
out = unfold(Render(e))
if !strings.Contains(out, `A\; B\, C \\ D`) {
t.Errorf("summary escaping wrong:\n%s", out)
}
// A newline inside a value must become the literal escape, never a real line break, or it terminates the
// property and everything after it is read as a new field.
e.Description = "line one\nline two\r\nline three"
out = Render(e)
for _, l := range strings.Split(out, "\r\n") {
if strings.HasPrefix(l, "line two") || strings.HasPrefix(l, "line three") {
t.Error("a newline in a value produced a real line break, breaking the object")
}
}
}
// A line over 75 octets is a protocol violation some clients reject and others mangle.
func TestLongLinesAreFolded(t *testing.T) {
e := sample()
e.Description = strings.Repeat("long description text ", 30)
out := Render(e)
for _, l := range strings.Split(out, "\r\n") {
if len(l) > 75 {
t.Errorf("unfolded line of %d octets: %q", len(l), l[:60])
}
}
// Folding must be REVERSIBLE. That is the property that matters, and it is what a client actually does:
// counting leading spaces would flag content that legitimately begins with one, since unfolding removes
// exactly one whitespace character and the rest is data.
if !strings.Contains(unfold(out), e.Description) {
t.Error("folding was not reversible, the description could not be recovered")
}
}
// A fold in the middle of a UTF-8 sequence produces a line no client can decode.
func TestFoldNeverSplitsAMultiByteCharacter(t *testing.T) {
e := sample()
// Repeated three byte characters, so a naive byte fold lands mid character somewhere.
e.Description = strings.Repeat("中", 200)
out := Render(e)
if !strings.Contains(out, "DESCRIPTION:") {
t.Fatal("description missing")
}
// Rejoining the folded property must reproduce the original characters exactly.
for _, l := range strings.Split(out, "\r\n") {
if len(l) > 75 {
t.Errorf("line too long: %d", len(l))
}
}
rejoined := strings.ReplaceAll(out, "\r\n ", "")
if !strings.Contains(rejoined, strings.Repeat("中", 200)) {
t.Error("folding corrupted a multi byte sequence")
}
}
// Times are always UTC with the trailing Z, so nobody has to agree with us about a time zone database.
func TestTimesAreUTC(t *testing.T) {
e := sample()
e.Start = time.Date(2026, 8, 3, 10, 0, 0, 0, time.FixedZone("EDT", -4*3600))
out := unfold(Render(e))
if !strings.Contains(out, "DTSTART:20260803T140000Z") {
t.Errorf("a local time was not converted to UTC:\n%s", out)
}
if strings.Count(out, "Z\r\n") < 3 {
t.Error("timestamps are missing the UTC designator")
}
}
// Without PARTSTAT and RSVP a calendar shows the entry with no way to accept, so the organiser never learns
// whether the candidate is coming.
func TestAttendeeCanRespond(t *testing.T) {
out := unfold(Render(sample()))
for _, want := range []string{
"METHOD:REQUEST", "STATUS:CONFIRMED",
"PARTSTAT=NEEDS-ACTION", "RSVP=TRUE",
"mailto:jordan@example.test", "mailto:talent@acme.test",
"BEGIN:VALARM", "TRIGGER:-PT15M",
} {
if !strings.Contains(out, want) {
t.Errorf("missing %q", want)
}
}
}
// A cancellation must be a CANCEL, or the meeting stays in the candidate's calendar with nobody attending.
func TestCancellation(t *testing.T) {
e := sample()
e.Cancelled = true
e.Sequence = 1
out := unfold(Render(e))
if !strings.Contains(out, "METHOD:CANCEL") || !strings.Contains(out, "STATUS:CANCELLED") {
t.Errorf("a cancellation did not render as one:\n%s", out)
}
if strings.Contains(out, "BEGIN:VALARM") {
t.Error("a cancelled event should not carry a reminder")
}
if !strings.Contains(out, "SEQUENCE:1") {
t.Error("a revision must carry a higher sequence or clients ignore it")
}
}
// A quote cannot be escaped inside a parameter value, so it must be removed rather than passed through.
func TestParameterEscaping(t *testing.T) {
e := sample()
e.AttendeeName = `Smith, Jane "JJ"`
out := unfold(Render(e))
if strings.Contains(out, `"JJ"`) {
t.Errorf("a quote survived into a parameter value:\n%s", out)
}
if !strings.Contains(out, `CN="Smith, Jane JJ"`) {
t.Errorf("a parameter containing a comma must be quoted:\n%s", out)
}
}
// The whole object must be CRLF terminated. LF only is the most common reason a correct invite is rejected.
func TestCRLFThroughout(t *testing.T) {
out := Render(sample())
if strings.Contains(strings.ReplaceAll(out, "\r\n", ""), "\n") {
t.Error("the object contains a bare LF")
}
if !strings.HasPrefix(out, "BEGIN:VCALENDAR\r\n") || !strings.HasSuffix(out, "END:VCALENDAR\r\n") {
t.Error("the object is not correctly delimited")
}
}