1 package xproto
2
3
21
22 import (
23 "fmt"
24 "log"
25 "math/rand"
26 "testing"
27 "time"
28
29 "github.com/jezek/xgb"
30 )
31
32
33 var X *xgb.Conn
34
35
36
37 func init() {
38 var err error
39
40 X, err = xgb.NewConn()
41 if err != nil {
42 log.Fatal(err)
43 }
44
45 rand.Seed(time.Now().UnixNano())
46
47 go grabEvents()
48 }
49
50
51
52
53
54
55
56 func TestSynchronousError(t *testing.T) {
57 err := MapWindowChecked(X, 0).Check()
58 if err == nil {
59 t.Fatalf("MapWindow: A MapWindow request that should return an " +
60 "error has returned a nil error.")
61 }
62 verifyMapWindowError(t, err)
63 }
64
65
66
67 func TestAsynchronousError(t *testing.T) {
68 MapWindow(X, 0)
69
70 evOrErr := waitForEvent(t, 5)
71 if evOrErr.ev != nil {
72 t.Fatalf("After issuing an erroneous MapWindow request, we have "+
73 "received an event rather than an error: %s", evOrErr.ev)
74 }
75 verifyMapWindowError(t, evOrErr.err)
76 }
77
78
79
80
81
82
83 func TestCookieBuffer(t *testing.T) {
84 n := (1 << 16) + 10
85 for i := 0; i < n; i++ {
86 NoOperation(X)
87 }
88 TestProperty(t)
89 }
90
91
92
93
94 func TestSequenceWrap(t *testing.T) {
95 n := (1 << 16) + 10
96 for i := 0; i < n; i++ {
97 _, err := InternAtom(X, false, 5, "RANDO").Reply()
98 if err != nil {
99 t.Fatalf("InternAtom: %s", err)
100 }
101 }
102 TestProperty(t)
103 }
104
105
106 func TestProperty(t *testing.T) {
107 propName := randString(20)
108 writeVal := randString(20)
109 readVal, err := changeAndGetProp(propName, writeVal)
110 if err != nil {
111 t.Error(err)
112 }
113
114 if readVal != writeVal {
115 t.Errorf("The value written, '%s', is not the same as the "+
116 "value read '%s'.", writeVal, readVal)
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132 func TestWindowEvents(t *testing.T) {
133
134 gx, gy, gw, gh := 200, 400, 1000, 300
135
136 wid, err := NewWindowId(X)
137 if err != nil {
138 t.Fatalf("NewId: %s", err)
139 }
140
141 screen := Setup(X).DefaultScreen(X)
142 err = CreateWindowChecked(X, screen.RootDepth, wid, screen.Root,
143 0, 0, 500, 500, 0,
144 WindowClassInputOutput, screen.RootVisual,
145 CwBackPixel|CwOverrideRedirect, []uint32{0xffffffff, 1}).Check()
146 if err != nil {
147 t.Fatalf("CreateWindow: %s", err)
148 }
149
150 err = MapWindowChecked(X, wid).Check()
151 if err != nil {
152 t.Fatalf("MapWindow: %s", err)
153 }
154
155
156
157 err = ChangeWindowAttributesChecked(X, wid,
158 CwEventMask, []uint32{EventMaskStructureNotify}).Check()
159 if err != nil {
160 t.Fatalf("ChangeWindowAttributes: %s", err)
161 }
162
163 err = ConfigureWindowChecked(X, wid,
164 ConfigWindowX|ConfigWindowY|
165 ConfigWindowWidth|ConfigWindowHeight,
166 []uint32{uint32(gx), uint32(gy), uint32(gw), uint32(gh)}).Check()
167 if err != nil {
168 t.Fatalf("ConfigureWindow: %s", err)
169 }
170
171 evOrErr := waitForEvent(t, 5)
172 switch event := evOrErr.ev.(type) {
173 case ConfigureNotifyEvent:
174 if event.X != int16(gx) {
175 t.Fatalf("x was set to %d but ConfigureNotify reports %d",
176 gx, event.X)
177 }
178 if event.Y != int16(gy) {
179 t.Fatalf("y was set to %d but ConfigureNotify reports %d",
180 gy, event.Y)
181 }
182 if event.Width != uint16(gw) {
183 t.Fatalf("width was set to %d but ConfigureNotify reports %d",
184 gw, event.Width)
185 }
186 if event.Height != uint16(gh) {
187 t.Fatalf("height was set to %d but ConfigureNotify reports %d",
188 gh, event.Height)
189 }
190 default:
191 t.Fatalf("Expected a ConfigureNotifyEvent but got %T instead.", event)
192 }
193
194
195 err = ChangeWindowAttributesChecked(X, wid,
196 CwEventMask, []uint32{0}).Check()
197 if err != nil {
198 t.Fatalf("ChangeWindowAttributes: %s", err)
199 }
200
201 err = DestroyWindowChecked(X, wid).Check()
202 if err != nil {
203 t.Fatalf("DestroyWindow: %s", err)
204 }
205 }
206
207
208 func TestGetFontPath(t *testing.T) {
209 fontPathReply, err := GetFontPath(X).Reply()
210 if err != nil {
211 t.Fatalf("GetFontPath: %v", err)
212 }
213 _ = fontPathReply
214 }
215
216 func TestListFonts(t *testing.T) {
217 listFontsReply, err := ListFonts(X, 10, 1, "*").Reply()
218 if err != nil {
219 t.Fatalf("ListFonts: %v", err)
220 }
221 _ = listFontsReply
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235 func BenchmarkInternAtomsGood(b *testing.B) {
236 b.StopTimer()
237 names := seqNames(b.N)
238
239 b.StartTimer()
240 cookies := make([]InternAtomCookie, b.N)
241 for i := 0; i < b.N; i++ {
242 cookies[i] = InternAtom(X, false, uint16(len(names[i])), names[i])
243 }
244 for _, cookie := range cookies {
245 cookie.Reply()
246 }
247 }
248
249
250
251
252
253 func BenchmarkInternAtomsPoor(b *testing.B) {
254 b.StopTimer()
255 names := seqNames(b.N)
256
257 b.StartTimer()
258 for i := 0; i < b.N; i++ {
259 InternAtom(X, false, uint16(len(names[i])), names[i]).Reply()
260 }
261 }
262
263
264
265
266
267
268
269
270
271
272 func changeAndGetProp(prop, val string) (string, error) {
273 setup := Setup(X)
274 root := setup.DefaultScreen(X).Root
275
276 propAtom, err := InternAtom(X, false, uint16(len(prop)), prop).Reply()
277 if err != nil {
278 return "", fmt.Errorf("InternAtom: %s", err)
279 }
280
281 typName := "UTF8_STRING"
282 typAtom, err := InternAtom(X, false, uint16(len(typName)), typName).Reply()
283 if err != nil {
284 return "", fmt.Errorf("InternAtom: %s", err)
285 }
286
287 err = ChangePropertyChecked(X, PropModeReplace, root, propAtom.Atom,
288 typAtom.Atom, 8, uint32(len(val)), []byte(val)).Check()
289 if err != nil {
290 return "", fmt.Errorf("ChangeProperty: %s", err)
291 }
292
293 reply, err := GetProperty(X, false, root, propAtom.Atom,
294 GetPropertyTypeAny, 0, (1<<32)-1).Reply()
295 if err != nil {
296 return "", fmt.Errorf("GetProperty: %s", err)
297 }
298 if reply.Format != 8 {
299 return "", fmt.Errorf("Property reply format is %d but it should be 8.",
300 reply.Format)
301 }
302
303 return string(reply.Value), nil
304 }
305
306
307
308
309 func verifyMapWindowError(t *testing.T, err error) {
310 switch e := err.(type) {
311 case WindowError:
312 if e.BadValue != 0 {
313 t.Fatalf("WindowError should report a bad value of 0 but "+
314 "it reports %d instead.", e.BadValue)
315 }
316 if e.MajorOpcode != 8 {
317 t.Fatalf("WindowError should report a major opcode of 8 "+
318 "(which is a MapWindow request), but it reports %d instead.",
319 e.MajorOpcode)
320 }
321 default:
322 t.Fatalf("Expected a WindowError but got %T instead.", e)
323 }
324 }
325
326
327 func randString(n int) string {
328 byts := make([]byte, n)
329 for i := 0; i < n; i++ {
330 rando := rand.Intn(53)
331 switch {
332 case rando <= 25:
333 byts[i] = byte(65 + rando)
334 case rando <= 51:
335 byts[i] = byte(97 + rando - 26)
336 default:
337 byts[i] = ' '
338 }
339 }
340 return string(byts)
341 }
342
343
344 func seqNames(n int) []string {
345 names := make([]string, n)
346 for i := range names {
347 names[i] = fmt.Sprintf("NAME%d", i)
348 }
349 return names
350 }
351
352
353 type evErr struct {
354 ev xgb.Event
355 err xgb.Error
356 }
357
358
359 var evOrErrChan = make(chan evErr, 0)
360
361
362
363
364 func grabEvents() {
365 for {
366 ev, err := X.WaitForEvent()
367 evOrErrChan <- evErr{ev, err}
368 }
369 }
370
371
372
373 func waitForEvent(t *testing.T, n int) evErr {
374 var evOrErr evErr
375
376 select {
377 case evOrErr = <-evOrErrChan:
378 case <-time.After(time.Second * 5):
379 t.Fatalf("After waiting 5 seconds for an event or an error, " +
380 "we have timed out.")
381 }
382
383 return evOrErr
384 }
385
View as plain text