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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package handlers
import (
"testing"
"time"
"task-dashboard/internal/models"
)
func multiDayEvent(startISO, endISO string) models.TimelineItem {
start, _ := time.Parse(time.RFC3339, startISO)
end, _ := time.Parse(time.RFC3339, endISO)
return models.TimelineItem{
ID: "evt-1",
Title: "Offsite",
Type: models.TimelineItemTypeEvent,
Time: start,
EndTime: &end,
}
}
func TestIsMultiDayEvent_SameDayTimedEvent_False(t *testing.T) {
item := multiDayEvent("2026-07-13T10:00:00Z", "2026-07-13T11:00:00Z")
if isMultiDayEvent(item) {
t.Error("expected same-day timed event to not be multi-day")
}
}
func TestIsMultiDayEvent_SpansMultipleDays_True(t *testing.T) {
item := multiDayEvent("2026-07-13T17:35:00Z", "2026-07-30T22:30:00Z")
if !isMultiDayEvent(item) {
t.Error("expected event spanning multiple days to be multi-day")
}
}
func TestIsMultiDayEvent_NonEventType_AlwaysFalse(t *testing.T) {
start, _ := time.Parse(time.RFC3339, "2026-07-13T10:00:00Z")
end, _ := time.Parse(time.RFC3339, "2026-07-30T22:30:00Z")
item := models.TimelineItem{ID: "t1", Type: models.TimelineItemTypeTask, Time: start, EndTime: &end}
if isMultiDayEvent(item) {
t.Error("expected non-event type to never be considered multi-day, regardless of span")
}
}
func TestIsMultiDayEvent_NoEndTime_False(t *testing.T) {
start, _ := time.Parse(time.RFC3339, "2026-07-13T10:00:00Z")
item := models.TimelineItem{ID: "e1", Type: models.TimelineItemTypeEvent, Time: start}
if isMultiDayEvent(item) {
t.Error("expected event with nil EndTime to not be multi-day")
}
}
func TestMultiDayVariant_StartDay_ReturnsStarts(t *testing.T) {
item := multiDayEvent("2026-07-13T17:35:00Z", "2026-07-30T22:30:00Z")
renderDay, _ := time.Parse(time.RFC3339, "2026-07-13T00:00:00Z")
if got := multiDayVariant(item, renderDay); got != "starts" {
t.Errorf("variant = %q, want %q", got, "starts")
}
}
func TestMultiDayVariant_EndDay_ReturnsEnds(t *testing.T) {
item := multiDayEvent("2026-07-13T17:35:00Z", "2026-07-30T22:30:00Z")
renderDay, _ := time.Parse(time.RFC3339, "2026-07-30T00:00:00Z")
if got := multiDayVariant(item, renderDay); got != "ends" {
t.Errorf("variant = %q, want %q", got, "ends")
}
}
func TestMultiDayVariant_MiddleDay_ReturnsSpans(t *testing.T) {
item := multiDayEvent("2026-07-13T17:35:00Z", "2026-07-30T22:30:00Z")
renderDay, _ := time.Parse(time.RFC3339, "2026-07-20T00:00:00Z")
if got := multiDayVariant(item, renderDay); got != "spans" {
t.Errorf("variant = %q, want %q", got, "spans")
}
}
func TestMultiDayVariant_DayOutsideSpan_ReturnsEmpty(t *testing.T) {
item := multiDayEvent("2026-07-13T17:35:00Z", "2026-07-30T22:30:00Z")
renderDay, _ := time.Parse(time.RFC3339, "2026-08-01T00:00:00Z")
if got := multiDayVariant(item, renderDay); got != "" {
t.Errorf("variant = %q, want empty", got)
}
}
func TestIsMultiDayEvent_SingleDayAllDayEvent_False(t *testing.T) {
// Exclusive end-date convention: a single-day all-day event on July 13
// has Start=Jul13 00:00, End=Jul14 00:00 (one day past its own day).
start, _ := time.Parse(time.RFC3339, "2026-07-13T00:00:00Z")
end, _ := time.Parse(time.RFC3339, "2026-07-14T00:00:00Z")
item := models.TimelineItem{
ID: "allday-1", Type: models.TimelineItemTypeEvent,
Time: start, EndTime: &end, IsAllDay: true,
}
if isMultiDayEvent(item) {
t.Error("expected a single-day all-day event (exclusive end-date) to not be multi-day")
}
}
func TestIsMultiDayEvent_MultiDayAllDayEvent_True(t *testing.T) {
// A 3-day all-day event (Jul 13, 14, 15) has End=Jul16 00:00 (exclusive).
start, _ := time.Parse(time.RFC3339, "2026-07-13T00:00:00Z")
end, _ := time.Parse(time.RFC3339, "2026-07-16T00:00:00Z")
item := models.TimelineItem{
ID: "allday-2", Type: models.TimelineItemTypeEvent,
Time: start, EndTime: &end, IsAllDay: true,
}
if !isMultiDayEvent(item) {
t.Error("expected a 3-day all-day event to be multi-day")
}
}
func TestMultiDayVariant_MultiDayAllDayEvent_LastRealDayIsEnds(t *testing.T) {
// The 3-day all-day event above (Jul 13-15 inclusive, End=Jul16 exclusive)
// must report "ends" on Jul 15 (its real last day), not Jul 16.
start, _ := time.Parse(time.RFC3339, "2026-07-13T00:00:00Z")
end, _ := time.Parse(time.RFC3339, "2026-07-16T00:00:00Z")
item := models.TimelineItem{
ID: "allday-2", Type: models.TimelineItemTypeEvent,
Time: start, EndTime: &end, IsAllDay: true,
}
renderDay, _ := time.Parse(time.RFC3339, "2026-07-15T00:00:00Z")
if got := multiDayVariant(item, renderDay); got != "ends" {
t.Errorf("variant on last real day = %q, want %q", got, "ends")
}
exclusiveEndDay, _ := time.Parse(time.RFC3339, "2026-07-16T00:00:00Z")
if got := multiDayVariant(item, exclusiveEndDay); got != "" {
t.Errorf("variant on the exclusive (non-real) end day = %q, want empty", got)
}
}
|