Turnpike/db_test.go

187 lines
5.3 KiB
Go
Raw Normal View History

package main
import (
"testing"
)
func TestMigrate(t *testing.T) {
app := testApp(t)
// Verify tables exist by querying each one
2026-03-10 15:27:49 -05:00
tables := []string{"event", "participants", "participant_roles", "departments", "volunteers", "shifts", "volunteer_shifts"}
for _, table := range tables {
var count int
err := app.db.QueryRow("SELECT COUNT(*) FROM " + table).Scan(&count)
if err != nil {
t.Errorf("table %s: %v", table, err)
}
}
}
func TestGenerateToken(t *testing.T) {
token, err := generateToken()
if err != nil {
t.Fatal(err)
}
if len(token) != 8 {
t.Errorf("token length = %d, want 8", len(token))
}
for _, c := range token {
if !isValidTokenChar(c) {
t.Errorf("invalid char %c in token %s", c, token)
}
}
}
func isValidTokenChar(c rune) bool {
for _, tc := range tokenChars {
if c == tc {
return true
}
}
return false
}
func TestGenerateUniqueToken(t *testing.T) {
app := testApp(t)
token, err := app.generateUniqueToken()
if err != nil || len(token) != 8 {
t.Fatalf("token=%q, err=%v", token, err)
}
}
func TestDepartmentsCRUD(t *testing.T) {
app := testApp(t)
d, err := app.createDepartment(Department{Name: "Gate"})
if err != nil {
t.Fatal(err)
}
if d.Name != "Gate" {
t.Errorf("name = %q", d.Name)
}
depts, _ := app.listDepartments("")
if len(depts) != 1 {
t.Errorf("list: got %d", len(depts))
}
if err := app.deleteDepartment(d.ID); err != nil {
t.Fatal(err)
}
}
func TestShiftsCRUD(t *testing.T) {
app := testApp(t)
dept, _ := app.createDepartment(Department{Name: "Gate"})
s, err := app.createShift(Shift{
DepartmentID: dept.ID,
Name: "Morning",
Day: "2026-03-15",
StartTime: "08:00",
EndTime: "12:00",
Capacity: 5,
})
if err != nil {
t.Fatal(err)
}
if s.Name != "Morning" || s.Capacity != 5 {
t.Errorf("create: %+v", s)
}
got, _ := app.getShift(s.ID)
if got == nil || got.Day != "2026-03-15" {
t.Error("get: not found or wrong day")
}
if err := app.deleteShift(s.ID); err != nil {
t.Fatal(err)
}
}
func TestAssignAndUnassignShift(t *testing.T) {
app := testApp(t)
dept, _ := app.createDepartment(Department{Name: "Gate"})
deptID := dept.ID
s, _ := app.createShift(Shift{DepartmentID: deptID, Name: "AM", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00", Capacity: 2})
p, _ := app.createParticipant(Participant{PreferredName: "Helena", Email: "helena@test.com"})
v, _ := app.createVolunteer(Volunteer{ParticipantID: p.ID, DepartmentID: &deptID})
if err := app.assignShift(v.ID, s.ID); err != nil {
t.Fatal(err)
}
count, _ := app.shiftAssignedCount(s.ID)
if count != 1 {
t.Errorf("assigned count = %d, want 1", count)
}
if err := app.unassignShift(v.ID, s.ID); err != nil {
t.Fatal(err)
}
count, _ = app.shiftAssignedCount(s.ID)
if count != 0 {
t.Errorf("after unassign: count = %d, want 0", count)
}
}
func TestCheckShiftConflict(t *testing.T) {
app := testApp(t)
dept, _ := app.createDepartment(Department{Name: "Gate"})
deptID := dept.ID
p, _ := app.createParticipant(Participant{PreferredName: "Hermia", Email: "hermia@test.com"})
v, _ := app.createVolunteer(Volunteer{ParticipantID: p.ID, DepartmentID: &deptID})
s1, _ := app.createShift(Shift{DepartmentID: deptID, Name: "Morning", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
s2, _ := app.createShift(Shift{DepartmentID: deptID, Name: "Overlap", Day: "2026-03-15", StartTime: "10:00", EndTime: "14:00"})
s3, _ := app.createShift(Shift{DepartmentID: deptID, Name: "NoOverlap", Day: "2026-03-15", StartTime: "14:00", EndTime: "18:00"})
app.assignShift(v.ID, s1.ID)
// s2 overlaps s1 (10:00-14:00 vs 08:00-12:00)
conflicts, err := app.checkShiftConflict(v.ID, s2.ID)
if err != nil {
t.Fatal(err)
}
if len(conflicts) != 1 {
t.Errorf("overlap: got %d conflicts, want 1", len(conflicts))
}
// s3 does not overlap s1 (14:00-18:00 vs 08:00-12:00)
conflicts, _ = app.checkShiftConflict(v.ID, s3.ID)
if len(conflicts) != 0 {
t.Errorf("no overlap: got %d conflicts, want 0", len(conflicts))
}
}
func TestCheckShiftConflictMidnight(t *testing.T) {
app := testApp(t)
dept, _ := app.createDepartment(Department{Name: "Sound"})
deptID := dept.ID
p, _ := app.createParticipant(Participant{PreferredName: "Lysander", Email: "lysander@test.com"})
v, _ := app.createVolunteer(Volunteer{ParticipantID: p.ID, DepartmentID: &deptID})
// Night shift: 22:00-02:00 (spans midnight)
night, _ := app.createShift(Shift{DepartmentID: deptID, Name: "Night", Day: "2026-03-15", StartTime: "22:00", EndTime: "02:00"})
// Late shift: 23:00-03:00 (overlaps with night)
late, _ := app.createShift(Shift{DepartmentID: deptID, Name: "Late", Day: "2026-03-15", StartTime: "23:00", EndTime: "03:00"})
// Morning shift: 08:00-12:00 (no overlap with night)
morning, _ := app.createShift(Shift{DepartmentID: deptID, Name: "Morning", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
app.assignShift(v.ID, night.ID)
// Late should conflict with night
conflicts, _ := app.checkShiftConflict(v.ID, late.ID)
if len(conflicts) != 1 {
t.Errorf("midnight overlap: got %d conflicts, want 1", len(conflicts))
}
// Morning should not conflict with night
conflicts, _ = app.checkShiftConflict(v.ID, morning.ID)
if len(conflicts) != 0 {
t.Errorf("no midnight overlap: got %d conflicts, want 0", len(conflicts))
}
}