73636f76a2
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 30s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 3m6s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 21s
Frontend additions in studio-v2:
- LehrerManager / FaecherManager / RaeumeManager — same CRUD pattern as
Klassen, with entity-specific form fields and table columns.
- regeln/TeacherUnavailableDayEditor — first constraint editor, joins
against teachersApi to render a readable name in the dropdown and
list. Falls back to a guidance banner when no teachers exist yet.
- page.tsx wires up the new tabs; data-testid attributes added across
managers so the Playwright suite can target them deterministically.
Tests:
- school-service: timetable_constraints_more_test.go fills the
remaining 9 constraint DTOs (TeacherMaxHoursDay/Week,
TeacherExcludedSubject/Room, SubjectMinDayGap,
SubjectContiguousWhenRepeated, SubjectDoubleLesson, ClassNoGaps,
RoomRequiresType). 66 subtests total, all green.
- studio-v2: e2e/stundenplan.spec.ts covers the page shell, tab
navigation, Klassen CRUD with mocked backend, constraint editor's
empty-teacher fallback, sidebar entry. All school-service calls
intercepted via page.route() so the suite is hermetic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
189 lines
6.4 KiB
Go
189 lines
6.4 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/breakpilot/school-service/internal/models"
|
|
)
|
|
|
|
// Additional validator tests covering the 9 constraint DTOs not exercised in
|
|
// timetable_constraints_test.go. Each entry probes both the happy path and
|
|
// the boundary that the binding tags are supposed to reject.
|
|
|
|
const (
|
|
uidTeacher = "00000000-0000-0000-0000-0000000000a1"
|
|
uidSubject = "00000000-0000-0000-0000-0000000000a2"
|
|
uidClass = "00000000-0000-0000-0000-0000000000a3"
|
|
uidRoom = "00000000-0000-0000-0000-0000000000a4"
|
|
)
|
|
|
|
func TestCreateTeacherMaxHoursDayRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateTeacherMaxHoursDayRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateTeacherMaxHoursDayRequest{TeacherID: uidTeacher, MaxHours: 6, IsHard: false, Weight: 50}, false},
|
|
{"missing teacher", models.CreateTeacherMaxHoursDayRequest{MaxHours: 6}, true},
|
|
{"hours below 1", models.CreateTeacherMaxHoursDayRequest{TeacherID: uidTeacher, MaxHours: 0}, true},
|
|
{"hours above 12", models.CreateTeacherMaxHoursDayRequest{TeacherID: uidTeacher, MaxHours: 13}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateTeacherMaxHoursWeekRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateTeacherMaxHoursWeekRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateTeacherMaxHoursWeekRequest{TeacherID: uidTeacher, MaxHours: 28, IsHard: true, Weight: 100}, false},
|
|
{"hours below 1", models.CreateTeacherMaxHoursWeekRequest{TeacherID: uidTeacher, MaxHours: 0}, true},
|
|
{"hours above 40", models.CreateTeacherMaxHoursWeekRequest{TeacherID: uidTeacher, MaxHours: 41}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateTeacherExcludedSubjectRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateTeacherExcludedSubjectRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateTeacherExcludedSubjectRequest{TeacherID: uidTeacher, SubjectID: uidSubject, IsHard: true, Weight: 100}, false},
|
|
{"missing subject", models.CreateTeacherExcludedSubjectRequest{TeacherID: uidTeacher}, true},
|
|
{"non-uuid subject", models.CreateTeacherExcludedSubjectRequest{TeacherID: uidTeacher, SubjectID: "nope"}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateTeacherExcludedRoomRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateTeacherExcludedRoomRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateTeacherExcludedRoomRequest{TeacherID: uidTeacher, RoomID: uidRoom, IsHard: true, Weight: 100}, false},
|
|
{"missing room", models.CreateTeacherExcludedRoomRequest{TeacherID: uidTeacher}, true},
|
|
{"non-uuid room", models.CreateTeacherExcludedRoomRequest{TeacherID: uidTeacher, RoomID: "nope"}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateSubjectMinDayGapRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateSubjectMinDayGapRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateSubjectMinDayGapRequest{SubjectID: uidSubject, MinGapDays: 1, IsHard: false, Weight: 70}, false},
|
|
{"below 1", models.CreateSubjectMinDayGapRequest{SubjectID: uidSubject, MinGapDays: 0}, true},
|
|
{"above 4", models.CreateSubjectMinDayGapRequest{SubjectID: uidSubject, MinGapDays: 5}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateSubjectContiguousWhenRepeatedRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateSubjectContiguousWhenRepeatedRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateSubjectContiguousWhenRepeatedRequest{SubjectID: uidSubject, IsHard: true, Weight: 100}, false},
|
|
{"missing subject", models.CreateSubjectContiguousWhenRepeatedRequest{}, true},
|
|
{"weight above 100", models.CreateSubjectContiguousWhenRepeatedRequest{SubjectID: uidSubject, Weight: 200}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateSubjectDoubleLessonRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateSubjectDoubleLessonRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateSubjectDoubleLessonRequest{SubjectID: uidSubject, IsHard: false, Weight: 60}, false},
|
|
{"missing subject", models.CreateSubjectDoubleLessonRequest{}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateClassNoGapsRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateClassNoGapsRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateClassNoGapsRequest{ClassID: uidClass, IsHard: false, Weight: 80}, false},
|
|
{"missing class", models.CreateClassNoGapsRequest{}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateRoomRequiresTypeRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
req models.CreateRoomRequiresTypeRequest
|
|
wantErr bool
|
|
}{
|
|
{"valid", models.CreateRoomRequiresTypeRequest{SubjectID: uidSubject, RoomType: "Sporthalle", IsHard: true, Weight: 100}, false},
|
|
{"missing room type", models.CreateRoomRequiresTypeRequest{SubjectID: uidSubject}, true},
|
|
{"non-uuid subject", models.CreateRoomRequiresTypeRequest{SubjectID: "x", RoomType: "y"}, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if (validate.Struct(tt.req) != nil) != tt.wantErr {
|
|
t.Errorf("unexpected validation outcome")
|
|
}
|
|
})
|
|
}
|
|
}
|