1package core_test
2
3import (
4 "testing"
5 "time"
6
7 "github.com/bnema/neferwl/internal/ports"
8)
9
10// A window that maps through the owner loop appears: the scene right after
11// the map shows it invisible at 90 %, a frame later it is in between, and it
12// settles exactly; its neighbour slides over. The client is configured once
13// per window. With animations off the first scene is the final one.
14func TestMapAnimates(t *testing.T) {
15 r := startSwipe(t, nil)
16 r.mapWindow(t, 1)
17 for len(r.commands) > 0 {
18 <-r.commands
19 }
20 first := r.multiRig.mapWindow(t, 2)[0]
21 w := windowOf(t, first, 2)
22 if w.Fade != 1 || w.Hidden {
23 t.Fatalf("new window right after the map: %+v", w)
24 }
25 if got := rectNow(t, first, 1); got.W != 800 {
26 t.Fatalf("neighbour right after the map is %d wide, want its old 800", got.W)
27 }
28 mid := r.frame(t, 30*time.Millisecond)
29 if m := windowOf(t, mid, 2); !(m.Fade > 0 && m.Fade < 1 && m.Rect.W > w.Rect.W && m.Rect.W < 400) {
30 t.Fatalf("new window on the first frame: %+v (was %+v)", m, w)
31 }
32 if got := rectNow(t, mid, 1).W; got <= 400 || got >= 800 {
33 t.Fatalf("neighbour on the first frame is %d wide, want between 400 and 800", got)
34 }
35 end := r.settle(t)
36 if m := windowOf(t, end, 2); m.Fade != 0 || m.Zoom != 0 || m.Rect.W != 400 {
37 t.Fatalf("settled new window: %+v", m)
38 }
39 if got := rectNow(t, end, 1).W; got != 400 {
40 t.Fatalf("settled neighbour is %d wide", got)
41 }
42 configures := map[ports.WindowID]int{}
43 for len(r.commands) > 0 {
44 if v, ok := (<-r.commands).(ports.ConfigureWindow); ok {
45 configures[v.ID]++
46 if v.Width != 400 {
47 t.Fatalf("configure to %d wide, want the final 400: %+v", v.Width, v)
48 }
49 }
50 }
51 if configures[2] != 1 || configures[1] != 1 {
52 t.Fatalf("configures %v, want one each", configures)
53 }
54}
55
56// With animations off a map shows the final layout at once.
57func TestMapAnimationsOffIsInstant(t *testing.T) {
58 r := startSwipe(t, animationsOff)
59 r.mapWindow(t, 1)
60 s := r.multiRig.mapWindow(t, 2)[0]
61 if w := windowOf(t, s, 2); w.Fade != 0 || w.Zoom != 0 || w.Rect.W != 400 {
62 t.Fatalf("new window: %+v", w)
63 }
64 if got := rectNow(t, s, 1).W; got != 400 {
65 t.Fatalf("neighbour is %d wide, want 400", got)
66 }
67 r.noFrameScene(t)
68}
69
70// A window that goes fullscreen right after its map drops its entrance.
71func TestMapFullscreenRequestDropsEntrance(t *testing.T) {
72 r := startSwipe(t, nil)
73 s := r.multiRig.mapWindow(t, 1)[0]
74 if windowOf(t, s, 1).Fade != 1 {
75 t.Fatal("no entrance to drop")
76 }
77 r.client <- ports.WindowFullscreenRequest{ID: 1, Fullscreen: true, External: true}
78 s = scene(t, r.scenes)
79 if w := windowOf(t, s, 1); w.Fade != 0 || w.Zoom != 0 || !w.Fullscreen {
80 t.Fatalf("fullscreen window still fading: %+v", w)
81 }
82}
83
84// A fullscreen request inside the grace after the map is ignored (Wine at a
85// remembered size): the entrance goes on.
86func TestMapFullscreenRequestWithinGraceKeepsEntrance(t *testing.T) {
87 r := startSwipe(t, nil)
88 s := r.multiRig.mapWindow(t, 1)[0]
89 if windowOf(t, s, 1).Fade != 1 {
90 t.Fatal("no entrance to keep")
91 }
92 r.client <- ports.WindowFullscreenRequest{ID: 1, Fullscreen: true}
93 // The flip is a barrier: the request is handled, a leftover scene dropped.
94 set, ok := r.clk.flip(t, r.frames, r.scenes, 30*time.Millisecond, wide.Name)
95 if !ok {
96 t.Fatal("no frame: the entrance stopped")
97 }
98 if w := windowOf(t, set[0], 1); w.Fullscreen || !(w.Fade > 0 && w.Fade < 1) {
99 t.Fatalf("ignored fullscreen request changed the window: %+v", w)
100 }
101}
102
103func windowOf(t *testing.T, s ports.Scene, id ports.WindowID) ports.SceneWindow {
104 t.Helper()
105 for _, w := range s.Windows {
106 if w.ID == id {
107 return w
108 }
109 }
110 t.Fatalf("window %d not in %+v", id, s.Windows)
111 return ports.SceneWindow{}
112}