|
|
|
@@ -330,6 +330,108 @@ func TestScheduling_CreateExceptionalGroup_NonAdmin(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Tests for 15-minute interval validation ---
|
|
|
|
|
|
|
|
|
|
// TestScheduling_UpdateDefaultHours_InvalidTimes verifies that UpdateDefaultHours
|
|
|
|
|
// rejects start_time/end_time with minutes not in {00, 15, 30, 45}.
|
|
|
|
|
func TestScheduling_UpdateDefaultHours_InvalidTimes(t *testing.T) {
|
|
|
|
|
handler := http.HandlerFunc(UpdateDefaultHours)
|
|
|
|
|
adminToken := jwt.GenerateAdminToken()
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
hours []DefaultHours
|
|
|
|
|
wantStatus int
|
|
|
|
|
}{
|
|
|
|
|
{"valid 00 minutes", []DefaultHours{{Weekday: 0, StartTime: "09:00", EndTime: "17:00", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid 15 minutes", []DefaultHours{{Weekday: 0, StartTime: "09:15", EndTime: "17:15", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid 30 minutes", []DefaultHours{{Weekday: 0, StartTime: "09:30", EndTime: "17:30", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid 45 minutes", []DefaultHours{{Weekday: 0, StartTime: "09:45", EndTime: "17:45", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid HH:MM:SS 00", []DefaultHours{{Weekday: 0, StartTime: "09:00:00", EndTime: "17:00:00", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid HH:MM:SS 15", []DefaultHours{{Weekday: 0, StartTime: "09:15:00", EndTime: "17:15:00", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid HH:MM:SS 30", []DefaultHours{{Weekday: 0, StartTime: "09:30:00", EndTime: "17:30:00", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"valid HH:MM:SS 45", []DefaultHours{{Weekday: 0, StartTime: "09:45:00", EndTime: "17:45:00", IsOpen: true}}, http.StatusNoContent},
|
|
|
|
|
{"invalid start_time :07", []DefaultHours{{Weekday: 0, StartTime: "09:07", EndTime: "17:00", IsOpen: true}}, http.StatusBadRequest},
|
|
|
|
|
{"invalid start_time :22", []DefaultHours{{Weekday: 0, StartTime: "09:22", EndTime: "17:00", IsOpen: true}}, http.StatusBadRequest},
|
|
|
|
|
{"invalid end_time :59", []DefaultHours{{Weekday: 0, StartTime: "09:00", EndTime: "17:59", IsOpen: true}}, http.StatusBadRequest},
|
|
|
|
|
{"invalid HH:MM:SS :07", []DefaultHours{{Weekday: 0, StartTime: "09:07:00", EndTime: "17:00:00", IsOpen: true}}, http.StatusBadRequest},
|
|
|
|
|
{"invalid HH:MM:SS :22", []DefaultHours{{Weekday: 0, StartTime: "09:22:00", EndTime: "17:00:00", IsOpen: true}}, http.StatusBadRequest},
|
|
|
|
|
{"invalid HH:MM:SS :59", []DefaultHours{{Weekday: 0, StartTime: "09:00:00", EndTime: "17:59:00", IsOpen: true}}, http.StatusBadRequest},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
resetTestData(t)
|
|
|
|
|
w := makeAuthRequest(handler, "PUT", "/api/scheduling/default-hours", adminToken, tt.hours)
|
|
|
|
|
if w.Code != tt.wantStatus {
|
|
|
|
|
t.Errorf("expected status %d, got %d. body: %s", tt.wantStatus, w.Code, w.Body.String())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestScheduling_CreateExceptionalGroup_InvalidTimes verifies that CreateExceptionalGroup
|
|
|
|
|
// rejects start_time/end_time with minutes not in {00, 15, 30, 45}.
|
|
|
|
|
func TestScheduling_CreateExceptionalGroup_InvalidTimes(t *testing.T) {
|
|
|
|
|
handler := http.HandlerFunc(CreateExceptionalGroup)
|
|
|
|
|
adminToken := jwt.GenerateAdminToken()
|
|
|
|
|
|
|
|
|
|
baseHours := func() []ExceptionalHours {
|
|
|
|
|
return []ExceptionalHours{
|
|
|
|
|
{Weekday: 0, StartTime: "08:00", EndTime: "18:00", IsOpen: true},
|
|
|
|
|
{Weekday: 1, StartTime: "08:00", EndTime: "18:00", IsOpen: true},
|
|
|
|
|
{Weekday: 2, StartTime: "08:00", EndTime: "18:00", IsOpen: true},
|
|
|
|
|
{Weekday: 3, StartTime: "08:00", EndTime: "18:00", IsOpen: true},
|
|
|
|
|
{Weekday: 4, StartTime: "08:00", EndTime: "18:00", IsOpen: true},
|
|
|
|
|
{Weekday: 5, StartTime: "09:00", EndTime: "17:00", IsOpen: true},
|
|
|
|
|
{Weekday: 6, StartTime: "00:00", EndTime: "00:00", IsOpen: false},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
modify func([]ExceptionalHours) []ExceptionalHours
|
|
|
|
|
wantStatus int
|
|
|
|
|
}{
|
|
|
|
|
{"valid times (00,15,30,45)", func(h []ExceptionalHours) []ExceptionalHours { return h }, http.StatusCreated},
|
|
|
|
|
{"valid HH:MM:SS (00,15,30,45)", func(h []ExceptionalHours) []ExceptionalHours {
|
|
|
|
|
h[0].StartTime = "08:00:00"
|
|
|
|
|
h[0].EndTime = "18:00:00"
|
|
|
|
|
h[1].StartTime = "09:15:00"
|
|
|
|
|
h[1].EndTime = "17:30:00"
|
|
|
|
|
return h
|
|
|
|
|
}, http.StatusCreated},
|
|
|
|
|
{"invalid start_time :07", func(h []ExceptionalHours) []ExceptionalHours { h[0].StartTime = "09:07"; return h }, http.StatusBadRequest},
|
|
|
|
|
{"invalid end_time :22", func(h []ExceptionalHours) []ExceptionalHours { h[0].EndTime = "17:22"; return h }, http.StatusBadRequest},
|
|
|
|
|
{"invalid start_time :59", func(h []ExceptionalHours) []ExceptionalHours { h[1].StartTime = "10:59"; return h }, http.StatusBadRequest},
|
|
|
|
|
{"invalid HH:MM:SS :07", func(h []ExceptionalHours) []ExceptionalHours {
|
|
|
|
|
h[0].StartTime = "09:07:00"
|
|
|
|
|
return h
|
|
|
|
|
}, http.StatusBadRequest},
|
|
|
|
|
{"invalid HH:MM:SS :59", func(h []ExceptionalHours) []ExceptionalHours {
|
|
|
|
|
h[1].EndTime = "18:59:00"
|
|
|
|
|
return h
|
|
|
|
|
}, http.StatusBadRequest},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
resetTestData(t)
|
|
|
|
|
hours := tt.modify(baseHours())
|
|
|
|
|
group := ExceptionalGroup{
|
|
|
|
|
Name: "Test Group",
|
|
|
|
|
Description: "Test",
|
|
|
|
|
Hours: hours,
|
|
|
|
|
WeekStarts: []string{"2026-06-01"},
|
|
|
|
|
}
|
|
|
|
|
w := makeAuthRequest(handler, "POST", "/api/scheduling/exceptional-groups", adminToken, group)
|
|
|
|
|
if w.Code != tt.wantStatus {
|
|
|
|
|
t.Errorf("expected status %d, got %d. body: %s", tt.wantStatus, w.Code, w.Body.String())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Tests for DeleteExceptionalGroup ---
|
|
|
|
|
|
|
|
|
|
// TestScheduling_DeleteExceptionalGroup_Admin tests that an admin can delete
|
|
|
|
@@ -673,3 +775,56 @@ func TestScheduling_GetAvailableHours_WithBlocker_Admin(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Direct unit tests for isValidTime15Min ---
|
|
|
|
|
|
|
|
|
|
// TestIsValidTime15Min tests the time validation helper directly for all
|
|
|
|
|
// supported formats (HH:MM, HH:MM:SS) and edge cases.
|
|
|
|
|
func TestIsValidTime15Min(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
time string
|
|
|
|
|
valid bool
|
|
|
|
|
}{
|
|
|
|
|
{"HH:MM 00", "09:00", true},
|
|
|
|
|
{"HH:MM 15", "09:15", true},
|
|
|
|
|
{"HH:MM 30", "09:30", true},
|
|
|
|
|
{"HH:MM 45", "09:45", true},
|
|
|
|
|
{"HH:MM :01", "09:01", false},
|
|
|
|
|
{"HH:MM :07", "09:07", false},
|
|
|
|
|
{"HH:MM :22", "09:22", false},
|
|
|
|
|
{"HH:MM :59", "09:59", false},
|
|
|
|
|
{"HH:MM:SS 00", "09:00:00", true},
|
|
|
|
|
{"HH:MM:SS 15", "09:15:00", true},
|
|
|
|
|
{"HH:MM:SS 30", "09:30:00", true},
|
|
|
|
|
{"HH:MM:SS 45", "09:45:00", true},
|
|
|
|
|
{"HH:MM:SS :01", "09:01:00", false},
|
|
|
|
|
{"HH:MM:SS :07", "09:07:00", false},
|
|
|
|
|
{"HH:MM:SS :22", "09:22:00", false},
|
|
|
|
|
{"HH:MM:SS :59", "09:59:00", false},
|
|
|
|
|
{"single-digit hour valid", "9:00", true},
|
|
|
|
|
{"single-digit hour invalid", "9:07", false},
|
|
|
|
|
{"midnight 00:00", "00:00", true},
|
|
|
|
|
{"midnight 00:00:00", "00:00:00", true},
|
|
|
|
|
{"empty string", "", false},
|
|
|
|
|
{"not a time", "abc", false},
|
|
|
|
|
{"single colon only", ":", false},
|
|
|
|
|
{"only colon numbers", ":15", false},
|
|
|
|
|
{"extra parts", "09:00:00:00", false},
|
|
|
|
|
{"hour only", "09", false},
|
|
|
|
|
{"garbage after colon", "09:xx", false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
got := isValidTime15Min(tt.time)
|
|
|
|
|
if got != tt.valid {
|
|
|
|
|
if tt.valid {
|
|
|
|
|
t.Errorf("isValidTime15Min(%q) = false, want true", tt.time)
|
|
|
|
|
} else {
|
|
|
|
|
t.Errorf("isValidTime15Min(%q) = true, want false", tt.time)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|