e958f88a2d
Phase 1 — Stammdaten (7 tables):
tt_class, tt_period, tt_room, tt_subject, tt_teacher,
tt_curriculum, tt_assignment with CRUD endpoints.
Phase 2 — Constraints (15 typed tables):
Teacher (6): unavailable_day, unavailable_window, max_hours_day,
max_hours_week, excluded_subject, excluded_room
Subject (5): min_day_gap, max_consecutive, contiguous_when_repeated,
preferred_period, double_lesson
Class (2): max_hours_day, no_gaps
Room (2): requires_type, unavailable
Each constraint row carries is_hard / weight / active / note /
created_by_user_id; ownership enforced via WHERE EXISTS against the
parent tt_teacher/tt_class/tt_subject/tt_room row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
5.1 KiB
Go
141 lines
5.1 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/breakpilot/school-service/internal/models"
|
|
)
|
|
|
|
// These tests exercise the request DTO binding tags (the same the Gin layer
|
|
// uses). They don't hit the database — DB-level checks live in integration
|
|
// tests against a real Postgres.
|
|
|
|
func TestCreateTeacherUnavailableDayRequest_Validation(t *testing.T) {
|
|
uid := "00000000-0000-0000-0000-000000000001"
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateTeacherUnavailableDayRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid monday", models.CreateTeacherUnavailableDayRequest{TeacherID: uid, DayOfWeek: 1, IsHard: true, Weight: 100, Active: true}, false},
|
|
{"day too low", models.CreateTeacherUnavailableDayRequest{TeacherID: uid, DayOfWeek: 0}, true},
|
|
{"day too high", models.CreateTeacherUnavailableDayRequest{TeacherID: uid, DayOfWeek: 8}, true},
|
|
{"non-uuid teacher", models.CreateTeacherUnavailableDayRequest{TeacherID: "not-a-uuid", DayOfWeek: 1}, true},
|
|
{"weight above 100", models.CreateTeacherUnavailableDayRequest{TeacherID: uid, DayOfWeek: 1, Weight: 150}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validate.Struct(tt.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateTeacherUnavailableWindowRequest_Validation(t *testing.T) {
|
|
uid := "00000000-0000-0000-0000-000000000001"
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateTeacherUnavailableWindowRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateTeacherUnavailableWindowRequest{TeacherID: uid, DayOfWeek: 2, StartTime: "13:00", EndTime: "17:00"}, false},
|
|
{"missing times", models.CreateTeacherUnavailableWindowRequest{TeacherID: uid, DayOfWeek: 2}, true},
|
|
{"day too high", models.CreateTeacherUnavailableWindowRequest{TeacherID: uid, DayOfWeek: 8, StartTime: "13:00", EndTime: "17:00"}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validate.Struct(tt.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateSubjectMaxConsecutiveRequest_Validation(t *testing.T) {
|
|
uid := "00000000-0000-0000-0000-000000000002"
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateSubjectMaxConsecutiveRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid 2 in a row", models.CreateSubjectMaxConsecutiveRequest{SubjectID: uid, MaxConsecutive: 2, IsHard: true, Weight: 100}, false},
|
|
{"below 1", models.CreateSubjectMaxConsecutiveRequest{SubjectID: uid, MaxConsecutive: 0}, true},
|
|
{"above 5", models.CreateSubjectMaxConsecutiveRequest{SubjectID: uid, MaxConsecutive: 6}, true},
|
|
{"non-uuid subject", models.CreateSubjectMaxConsecutiveRequest{SubjectID: "x", MaxConsecutive: 2}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validate.Struct(tt.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateSubjectPreferredPeriodRequest_Validation(t *testing.T) {
|
|
uid := "00000000-0000-0000-0000-000000000002"
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateSubjectPreferredPeriodRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid morning", models.CreateSubjectPreferredPeriodRequest{SubjectID: uid, PeriodFrom: 1, PeriodTo: 4, IsHard: false, Weight: 40}, false},
|
|
{"from missing", models.CreateSubjectPreferredPeriodRequest{SubjectID: uid, PeriodTo: 4}, true},
|
|
{"to too high", models.CreateSubjectPreferredPeriodRequest{SubjectID: uid, PeriodFrom: 1, PeriodTo: 13}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validate.Struct(tt.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateClassMaxHoursDayRequest_Validation(t *testing.T) {
|
|
uid := "00000000-0000-0000-0000-000000000003"
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateClassMaxHoursDayRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateClassMaxHoursDayRequest{ClassID: uid, MaxHours: 6, IsHard: true, Weight: 100}, false},
|
|
{"hours below 1", models.CreateClassMaxHoursDayRequest{ClassID: uid, MaxHours: 0}, true},
|
|
{"hours above 12", models.CreateClassMaxHoursDayRequest{ClassID: uid, MaxHours: 13}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validate.Struct(tt.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateRoomUnavailableRequest_Validation(t *testing.T) {
|
|
uid := "00000000-0000-0000-0000-000000000004"
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateRoomUnavailableRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateRoomUnavailableRequest{RoomID: uid, DayOfWeek: 3, PeriodIndex: 4, IsHard: true, Weight: 100}, false},
|
|
{"missing day", models.CreateRoomUnavailableRequest{RoomID: uid, PeriodIndex: 4}, true},
|
|
{"period too high", models.CreateRoomUnavailableRequest{RoomID: uid, DayOfWeek: 3, PeriodIndex: 13}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validate.Struct(tt.req)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|