Build Ground Station / build (push) Successful in 37s
Drive two independent visual layers per display target from one shared video presence signal: the fullscreen fallback/menu canvas below video and a transparent, input-transparent OSD overlay above video, reserved as the future flight OSD rendering surface. WFB and video decode stay out of the UI process; pilot video keeps rendering priority.
86 lines
2.8 KiB
Go
86 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.piksar.eu/piotr/groundstation/internal/display"
|
|
)
|
|
|
|
type recordingCanvas struct {
|
|
width, height int
|
|
lines []string
|
|
clears, flushes int
|
|
}
|
|
|
|
func (c *recordingCanvas) Size() (int, int) { return c.width, c.height }
|
|
func (c *recordingCanvas) Clear() { c.clears++ }
|
|
func (c *recordingCanvas) Text(_, _ int, message string) {
|
|
c.lines = append(c.lines, message)
|
|
}
|
|
func (c *recordingCanvas) Flush() { c.flushes++ }
|
|
|
|
func TestBuildTargetBuildsIndependentVitureLayers(t *testing.T) {
|
|
layers, err := buildTarget("x11")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(layers) != 2 {
|
|
t.Fatalf("layers=%d want the fallback canvas and the OSD overlay", len(layers))
|
|
}
|
|
canvas, osd := layers[0], layers[1]
|
|
if canvas.Name != "fallback-canvas" || osd.Name != "osd-overlay" {
|
|
t.Fatalf("layer names %q/%q want fallback-canvas/osd-overlay", canvas.Name, osd.Name)
|
|
}
|
|
|
|
canvasOpener, ok := canvas.Opener.(display.X11Opener)
|
|
if !ok {
|
|
t.Fatalf("canvas opener %T must be the X11 target", canvas.Opener)
|
|
}
|
|
if canvasOpener.Role != display.RoleBelow {
|
|
t.Fatalf("canvas layer role %v must stay below video", canvasOpener.Role)
|
|
}
|
|
osdOpener, ok := osd.Opener.(display.X11Opener)
|
|
if !ok {
|
|
t.Fatalf("OSD opener %T must be the X11 target", osd.Opener)
|
|
}
|
|
if osdOpener.Role != display.RoleAbove {
|
|
t.Fatalf("OSD layer role %v must stay above video", osdOpener.Role)
|
|
}
|
|
|
|
// Both layers must share one presence signal so the video lifecycle
|
|
// observed by either session drives both templates.
|
|
if canvasOpener.Video == nil || osdOpener.Video == nil || canvasOpener.Video != osdOpener.Video {
|
|
t.Fatal("layers must share one video presence signal")
|
|
}
|
|
|
|
// The canvas layer keeps the target-specific fallback template with the
|
|
// exact fallback text.
|
|
canvasSurface := &recordingCanvas{width: 800, height: 600}
|
|
canvas.Template.Draw(canvasSurface)
|
|
if len(canvasSurface.lines) != 1 || canvasSurface.lines[0] != "Brak połączenia WFB" {
|
|
t.Fatalf("canvas lines=%q want the exact fallback text", canvasSurface.lines)
|
|
}
|
|
|
|
// The OSD layer is the OSD surface, never the fallback.
|
|
osdSurface := &recordingCanvas{width: 800, height: 600}
|
|
osd.Template.Draw(osdSurface)
|
|
if len(osdSurface.lines) != 0 {
|
|
t.Fatalf("OSD lines=%q want none: the overlay must not duplicate the fallback", osdSurface.lines)
|
|
}
|
|
|
|
// Video presence hides the fallback on the canvas layer only.
|
|
canvasOpener.Video.SetActive(true)
|
|
canvasSurface.lines = nil
|
|
canvas.Template.Draw(canvasSurface)
|
|
if len(canvasSurface.lines) != 0 {
|
|
t.Fatalf("canvas lines=%q must disappear while video is present", canvasSurface.lines)
|
|
}
|
|
canvasOpener.Video.SetActive(false)
|
|
}
|
|
|
|
func TestBuildTargetRejectsUnknownTarget(t *testing.T) {
|
|
if _, err := buildTarget("hdmi-mirror"); err == nil {
|
|
t.Fatal("unknown target must fail")
|
|
}
|
|
}
|