package messagewall import ( "strings" "testing" ) func TestResolveBuildsScenes(t *testing.T) { request := ResolveRequest{ Layout: Layout{ Version: 1, CoordinateSpace: CoordinateSpace{ Width: 200, Height: 100, Unit: "grid", }, FitMode: "cover", Slots: []Slot{ {SlotID: "wall-r1-c2", X: 100, Y: 0, Width: 100, Height: 100}, {SlotID: "wall-r1-c1", X: 0, Y: 0, Width: 100, Height: 100}, }, }, Source: "/media/banner.png", DurationSeconds: 30, LoadTimeoutSeconds: 12, OnError: "skip", } result, err := Resolve(request) if err != nil { t.Fatalf("Resolve() error = %v", err) } if got, want := len(result.Scenes), 2; got != want { t.Fatalf("len(result.Scenes) = %d, want %d", got, want) } if got, want := result.Scenes[0].SlotID, "wall-r1-c1"; got != want { t.Fatalf("first SlotID = %s, want %s", got, want) } if got, want := result.Scenes[1].Crop.X, 100; got != want { t.Fatalf("second Crop.X = %d, want %d", got, want) } } func TestValidateRejectsOverlappingSlots(t *testing.T) { layout := Layout{ Version: 1, CoordinateSpace: CoordinateSpace{ Width: 100, Height: 100, Unit: "grid", }, FitMode: "cover", Slots: []Slot{ {SlotID: "a", X: 0, Y: 0, Width: 60, Height: 60}, {SlotID: "b", X: 50, Y: 0, Width: 50, Height: 50}, }, } if err := Validate(layout); err == nil { t.Fatal("Validate() error = nil, want overlap error") } } func TestValidateRejectsDocumentedInvalidLayouts(t *testing.T) { tests := []struct { name string layout Layout wantMessage string }{ { name: "unsupported version", layout: Layout{ Version: 2, CoordinateSpace: CoordinateSpace{Width: 100, Height: 100, Unit: "grid"}, FitMode: "cover", Slots: []Slot{{SlotID: "a", X: 0, Y: 0, Width: 100, Height: 100}}, }, wantMessage: "unsupported layout version", }, { name: "unsupported unit", layout: Layout{ Version: 1, CoordinateSpace: CoordinateSpace{Width: 100, Height: 100, Unit: "pixel"}, FitMode: "cover", Slots: []Slot{{SlotID: "a", X: 0, Y: 0, Width: 100, Height: 100}}, }, wantMessage: "unsupported coordinate_space unit", }, { name: "unsupported fit mode", layout: Layout{ Version: 1, CoordinateSpace: CoordinateSpace{Width: 100, Height: 100, Unit: "grid"}, FitMode: "stretch", Slots: []Slot{{SlotID: "a", X: 0, Y: 0, Width: 100, Height: 100}}, }, wantMessage: "unsupported fit_mode", }, { name: "empty slots", layout: Layout{ Version: 1, CoordinateSpace: CoordinateSpace{Width: 100, Height: 100, Unit: "grid"}, FitMode: "cover", }, wantMessage: "layout must contain at least one slot", }, { name: "duplicate slot ids", layout: Layout{ Version: 1, CoordinateSpace: CoordinateSpace{Width: 100, Height: 100, Unit: "grid"}, FitMode: "cover", Slots: []Slot{ {SlotID: "a", X: 0, Y: 0, Width: 50, Height: 100}, {SlotID: "a", X: 50, Y: 0, Width: 50, Height: 100}, }, }, wantMessage: "duplicate slot_id", }, { name: "slot exceeds bounds", layout: Layout{ Version: 1, CoordinateSpace: CoordinateSpace{Width: 100, Height: 100, Unit: "grid"}, FitMode: "cover", Slots: []Slot{{SlotID: "a", X: 60, Y: 0, Width: 50, Height: 100}}, }, wantMessage: "exceeds coordinate_space width", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := Validate(tt.layout) if err == nil { t.Fatal("Validate() error = nil, want validation error") } if !strings.Contains(err.Error(), tt.wantMessage) { t.Fatalf("Validate() error = %q, want message containing %q", err.Error(), tt.wantMessage) } }) } }