1package app
2
3import (
4 "encoding/binary"
5 "testing"
6)
7
8func state(vals ...uint32) []byte {
9 var b []byte
10 for _, v := range vals {
11 b = binary.NativeEndian.AppendUint32(b, v)
12 }
13 return b
14}
15
16// open maps a window: its properties and its state, then the done that applies them.
17func open(t *Tracker, h uint32, id, title string, st ...uint32) {
18 t.ID(h, id)
19 t.Title(h, title)
20 t.State(h, state(st...))
21 t.Done(h)
22}
23
24func TestNothingFocusedIsTheZeroWindow(t *testing.T) {
25 tr := NewTracker()
26 if tr.Focused() != (Window{}) {
27 t.Fatal("an empty tracker must have no focus")
28 }
29 open(tr, 1, "a", "A") // mapped, not activated
30 if tr.Focused() != (Window{}) {
31 t.Fatalf("a window without the activated state has no focus: %+v", tr.Focused())
32 }
33}
34
35func TestFocusFollowsTheActivatedState(t *testing.T) {
36 tr := NewTracker()
37 open(tr, 1, "org.mozilla.firefox", "Docs", 0, stateActivated) // maximized + activated
38 open(tr, 2, "kitty", "~")
39 if got := tr.Focused(); got != (Window{"org.mozilla.firefox", "Docs"}) {
40 t.Fatalf("focused = %+v", got)
41 }
42 // Focus moves: 1 loses it, 2 gets it.
43 open(tr, 1, "org.mozilla.firefox", "Docs", 0)
44 open(tr, 2, "kitty", "~", stateActivated)
45 if got := tr.Focused(); got != (Window{"kitty", "~"}) {
46 t.Fatalf("after the focus moved: %+v", got)
47 }
48}
49
50func TestATitleChangeAppliesOnlyAtDone(t *testing.T) {
51 tr := NewTracker()
52 open(tr, 1, "kitty", "one", stateActivated)
53 tr.Title(1, "two")
54 if got := tr.Focused().Title; got != "one" {
55 t.Fatalf("title changed before done: %q", got)
56 }
57 tr.Done(1)
58 if got := tr.Focused().Title; got != "two" {
59 t.Fatalf("title after done: %q", got)
60 }
61}
62
63func TestClosingTheFocusedWindowClearsTheFocus(t *testing.T) {
64 tr := NewTracker()
65 open(tr, 1, "kitty", "~", stateActivated)
66 tr.Closed(1)
67 if tr.Focused() != (Window{}) {
68 t.Fatalf("a closed window still has the focus: %+v", tr.Focused())
69 }
70}
71
72func TestTheWindowThatGotTheFocusLastWins(t *testing.T) {
73 tr := NewTracker()
74 open(tr, 1, "a", "A", stateActivated)
75 open(tr, 2, "b", "B", stateActivated) // two seats, two focused windows
76 if got := tr.Focused().ID; got != "b" {
77 t.Fatalf("focused = %q, want b (the newest)", got)
78 }
79 open(tr, 1, "a", "A2", stateActivated) // still active, only its title changed
80 if got := tr.Focused().ID; got != "b" {
81 t.Fatalf("a title change must not steal the focus: %q", got)
82 }
83}
84
85func TestCleanRemovesControlCharacters(t *testing.T) {
86 in := "fire\x1b[2Jfox\n\ttab\x07 ok \u00e9"
87 if got, want := Clean(in), "fire[2Jfoxtab ok \u00e9"; got != want {
88 t.Fatalf("Clean = %q, want %q", got, want)
89 }
90}
91
92func TestNameIsTheLastPartOfTheID(t *testing.T) {
93 for id, want := range map[string]string{
94 "com.github.bnema.dumber": "dumber",
95 "org.mozilla.firefox": "firefox",
96 "kitty": "kitty",
97 "": "",
98 "trailing.": "trailing.",
99 } {
100 if got := Name(id); got != want {
101 t.Errorf("Name(%q) = %q, want %q", id, got, want)
102 }
103 }
104}