This commit is contained in:
2026-10-28 23:52:03 +07:00
parent e16c52544e
commit 1676ccdffb
2 changed files with 49 additions and 2 deletions
@@ -90,6 +90,12 @@ func TestPackagePreservesPregameData(t *testing.T) {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
snapshot, files := fixture() snapshot, files := fixture()
snapshot.Data.Game.Format = tc.format snapshot.Data.Game.Format = tc.format
snapshot.Data.ScreenPlan.Steps = append(snapshot.Data.ScreenPlan.Steps,
game_screen_plans_repo.Step{Mode: 6},
game_screen_plans_repo.Step{Mode: 9, QRURL: "https://example.org", Text: "QR"},
game_screen_plans_repo.Step{Mode: 10},
game_screen_plans_repo.Step{Mode: 7, TimerType: 1, TimerDurationSeconds: 60, TimerLabel: "До начала игры"},
)
if tc.format == "offline" { if tc.format == "offline" {
snapshot.Data.Game.WiFiName = "Детектив" snapshot.Data.Game.WiFiName = "Детектив"
snapshot.Data.Game.WiFiPassword = " secret " snapshot.Data.Game.WiFiPassword = " secret "
@@ -194,7 +200,7 @@ func TestPackRejectsInvalidSnapshot(t *testing.T) {
{"duplicate map item", func(s *Snapshot) { s.Data.Map = append(s.Data.Map, s.Data.Map[0]) }}, {"duplicate map item", func(s *Snapshot) { s.Data.Map = append(s.Data.Map, s.Data.Map[0]) }},
{"invalid organizer desk", func(s *Snapshot) { s.Data.Map[1].ItemID = "" }}, {"invalid organizer desk", func(s *Snapshot) { s.Data.Map[1].ItemID = "" }},
{"invalid plan index", func(s *Snapshot) { s.Data.ScreenPlan.CurrentStep = 10 }}, {"invalid plan index", func(s *Snapshot) { s.Data.ScreenPlan.CurrentStep = 10 }},
{"invalid plan mode", func(s *Snapshot) { s.Data.ScreenPlan.Steps[0].Mode = 9 }}, {"invalid plan mode", func(s *Snapshot) { s.Data.ScreenPlan.Steps[0].Mode = 11 }},
} { } {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
snapshot, files := fixture() snapshot, files := fixture()
@@ -838,3 +844,41 @@ func TestRewriteMediaChecksAllNamesBeforeMutation(t *testing.T) {
}) })
} }
} }
func TestPackageValidatesScreenSteps(t *testing.T) {
for _, tc := range []struct {
name string
step game_screen_plans_repo.Step
valid bool
}{
{"cover", game_screen_plans_repo.Step{Mode: 1}, true},
{"intro", game_screen_plans_repo.Step{Mode: 2}, true},
{"conclusion", game_screen_plans_repo.Step{Mode: 4}, true},
{"results before game", game_screen_plans_repo.Step{Mode: 6}, true},
{"timer", game_screen_plans_repo.Step{Mode: 7, TimerDurationSeconds: 60}, true},
{"text", game_screen_plans_repo.Step{Mode: 8, Text: "Hello"}, true},
{"QR", game_screen_plans_repo.Step{Mode: 9, QRURL: "https://example.org"}, true},
{"teams", game_screen_plans_repo.Step{Mode: 10}, true},
{"unspecified", game_screen_plans_repo.Step{Mode: 0}, false},
{"removed intro", game_screen_plans_repo.Step{Mode: 3}, false},
{"removed conclusion", game_screen_plans_repo.Step{Mode: 5}, false},
{"unknown", game_screen_plans_repo.Step{Mode: 11}, false},
{"missing QR", game_screen_plans_repo.Step{Mode: 9}, false},
{"unsafe QR", game_screen_plans_repo.Step{Mode: 9, QRURL: "javascript:alert(1)"}, false},
{"invalid timer type", game_screen_plans_repo.Step{Mode: 7, TimerDurationSeconds: 60, TimerType: 3}, false},
{"negative timer type", game_screen_plans_repo.Step{Mode: 1, TimerType: -1}, false},
} {
t.Run(tc.name, func(t *testing.T) {
snapshot, _ := fixture()
snapshot.Data.ScreenPlan.Steps = []game_screen_plans_repo.Step{tc.step}
snapshot.Data.ScreenPlan.CurrentStep = 0
err := validateData(&snapshot.Data)
if tc.valid && err != nil {
t.Fatal(err)
}
if !tc.valid && !errors.Is(err, ErrInvalidPackage) {
t.Fatalf("expected invalid package, got %v", err)
}
})
}
}
@@ -10,6 +10,7 @@ import (
"unicode" "unicode"
"evening_detective_server/internal/modules/team_qr_pdf" "evening_detective_server/internal/modules/team_qr_pdf"
"evening_detective_server/internal/services/screen_service"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -156,7 +157,9 @@ func validateData(data *Data) error {
return invalid("некорректный план экранов") return invalid("некорректный план экранов")
} }
for _, step := range plan.Steps { for _, step := range plan.Steps {
if step.Mode < 1 || step.Mode > 8 || if !screen_service.ValidMode(step.Mode) ||
!screen_service.ValidTimerType(step.TimerType) ||
(step.Mode == 9 && !screen_service.ValidQR(step.QRURL, step.Text)) ||
(step.Mode == 7 && (step.TimerDurationSeconds <= 0 || step.TimerDurationSeconds > 86400 || len(step.TimerLabel) > 200)) || (step.Mode == 7 && (step.TimerDurationSeconds <= 0 || step.TimerDurationSeconds > 86400 || len(step.TimerLabel) > 200)) ||
(step.Mode == 8 && (strings.TrimSpace(step.Text) == "" || len(step.Text) > 10000)) { (step.Mode == 8 && (strings.TrimSpace(step.Text) == "" || len(step.Text) > 10000)) {
return invalid("некорректный шаг плана экранов") return invalid("некорректный шаг плана экранов")