VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/testcase/tstSeamlessX11-auto.cpp@ 33983

Last change on this file since 33983 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.8 KB
Line 
1/** @file
2 * Automated test of the X11 seamless Additions code.
3 */
4
5/*
6 * Copyright (C) 2007 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include <iostream>
18#include <stdlib.h> /* exit() */
19
20#include <X11/Xatom.h>
21#include <X11/Xmu/WinUtil.h>
22
23#include <iprt/initterm.h>
24#include <iprt/mem.h>
25#include <iprt/path.h>
26#include <iprt/semaphore.h>
27#include <iprt/stream.h>
28#include <iprt/string.h>
29
30#include "../seamless.h"
31
32#undef DefaultRootWindow
33
34/******************************************************
35* Mock X11 functions needed by the seamless X11 class *
36******************************************************/
37
38int XFree(void *data)
39{
40 RTMemFree(data);
41 return 0;
42}
43
44#define TEST_DISPLAY ((Display *)0xffff)
45#define TEST_ROOT ((Window)1)
46
47extern "C" Display *XOpenDisplay(const char *display_name);
48Display *XOpenDisplay(const char *display_name)
49{
50 return TEST_DISPLAY;
51}
52
53extern "C" int XCloseDisplay(Display *display);
54int XCloseDisplay(Display *display)
55{
56 Assert(display == TEST_DISPLAY);
57 return 0;
58}
59
60enum
61{
62 ATOM_PROP = 1,
63 ATOM_DESKTOP_PROP
64};
65
66extern "C" Atom XInternAtom(Display *display, const char *atom_name,
67 Bool only_if_exists);
68Atom XInternAtom(Display *display, const char *atom_name, Bool only_if_exists)
69{
70 if (!RTStrCmp(atom_name, WM_TYPE_PROP))
71 return (Atom) ATOM_PROP;
72 if (!RTStrCmp(atom_name, WM_TYPE_DESKTOP_PROP))
73 return (Atom) ATOM_DESKTOP_PROP;
74 AssertFailed();
75 return (Atom)0;
76}
77
78/** The window (if any) on which the WM_TYPE_PROP property is set to the
79 * WM_TYPE_DESKTOP_PROP atom. */
80static Window g_hSmlsDesktopWindow = 0;
81
82extern "C" int XGetWindowProperty(Display *display, Window w, Atom property,
83 long long_offset, long long_length,
84 Bool delProp, Atom req_type,
85 Atom *actual_type_return,
86 int *actual_format_return,
87 unsigned long *nitems_return,
88 unsigned long *bytes_after_return,
89 unsigned char **prop_return);
90int XGetWindowProperty(Display *display, Window w, Atom property,
91 long long_offset, long long_length, Bool delProp,
92 Atom req_type, Atom *actual_type_return,
93 int *actual_format_return,
94 unsigned long *nitems_return,
95 unsigned long *bytes_after_return,
96 unsigned char **prop_return)
97{
98 Atom atomType = XInternAtom (NULL, WM_TYPE_PROP, true);
99 Atom atomTypeDesktop = XInternAtom (NULL, WM_TYPE_DESKTOP_PROP, true);
100 /* We only handle things we expect. */
101 AssertReturn((req_type == XA_ATOM) || (req_type == AnyPropertyType),
102 0xffff);
103 AssertReturn(property == atomType, 0xffff);
104 *actual_type_return = XA_ATOM;
105 *actual_format_return = sizeof(Atom) * 8;
106 *nitems_return = 0;
107 *bytes_after_return = sizeof(Atom);
108 *prop_return = NULL;
109 if ((w != g_hSmlsDesktopWindow) || (g_hSmlsDesktopWindow == 0))
110 return Success;
111 AssertReturn(long_offset == 0, 0);
112 AssertReturn(delProp == false, 0);
113 unsigned char *pProp;
114 pProp = (unsigned char *)RTMemDup(&atomTypeDesktop,
115 sizeof(atomTypeDesktop));
116 AssertReturn(pProp, 0xffff);
117 *nitems_return = 1;
118 *prop_return = pProp;
119 *bytes_after_return = 0;
120 return 0;
121}
122
123/** Sets the current set of properties for all mock X11 windows */
124static void smlsSetDesktopWindow(Window hWin)
125{
126 g_hSmlsDesktopWindow = hWin;
127}
128
129extern "C" Bool XShapeQueryExtension (Display *dpy, int *event_basep,
130 int *error_basep);
131Bool XShapeQueryExtension (Display *dpy, int *event_basep, int *error_basep)
132{
133 return true;
134}
135
136/* We silently ignore this for now. */
137extern "C" int XSelectInput(Display *display, Window w, long event_mask);
138int XSelectInput(Display *display, Window w, long event_mask)
139{
140 return 0;
141}
142
143/* We silently ignore this for now. */
144extern "C" void XShapeSelectInput(Display *display, Window w,
145 unsigned long event_mask);
146void XShapeSelectInput(Display *display, Window w, unsigned long event_mask)
147{}
148
149extern "C" Window XDefaultRootWindow(Display *display);
150Window XDefaultRootWindow(Display *display)
151{
152 return TEST_ROOT;
153}
154
155static unsigned g_cSmlsWindows = 0;
156static Window *g_paSmlsWindows = NULL;
157static XWindowAttributes *g_paSmlsWinAttribs = NULL;
158static const char **g_papszSmlsWinNames = NULL;
159
160extern "C" Status XQueryTree(Display *display, Window w, Window *root_return,
161 Window *parent_return, Window **children_return,
162 unsigned int *nchildren_return);
163Status XQueryTree(Display *display, Window w, Window *root_return,
164 Window *parent_return, Window **children_return,
165 unsigned int *nchildren_return)
166{
167 AssertReturn(w == TEST_ROOT, False); /* We support nothing else */
168 AssertPtrReturn(children_return, False);
169 AssertReturn(g_paSmlsWindows, False);
170 if (root_return)
171 *root_return = TEST_ROOT;
172 if (parent_return)
173 *parent_return = TEST_ROOT;
174 *children_return = (Window *)RTMemDup(g_paSmlsWindows,
175 g_cSmlsWindows * sizeof(Window));
176 if (nchildren_return)
177 *nchildren_return = g_cSmlsWindows;
178 return (g_cSmlsWindows != 0);
179}
180
181extern "C" Window XmuClientWindow(Display *dpy, Window win);
182Window XmuClientWindow(Display *dpy, Window win)
183{
184 return win;
185}
186
187extern "C" Status XGetWindowAttributes(Display *display, Window w,
188 XWindowAttributes *window_attributes_return);
189Status XGetWindowAttributes(Display *display, Window w,
190 XWindowAttributes *window_attributes_return)
191{
192 AssertPtrReturn(window_attributes_return, 1);
193 for (unsigned i = 0; i < g_cSmlsWindows; ++i)
194 if (g_paSmlsWindows[i] == w)
195 {
196 *window_attributes_return = g_paSmlsWinAttribs[i];
197 return 1;
198 }
199 return 0;
200}
201
202extern "C" Status XGetWMNormalHints(Display *display, Window w,
203 XSizeHints *hints_return,
204 long *supplied_return);
205
206Status XGetWMNormalHints(Display *display, Window w,
207 XSizeHints *hints_return, long *supplied_return)
208{
209 return 1;
210}
211
212static void smlsSetWindowAttributes(XWindowAttributes *pAttribs,
213 Window *pWindows, unsigned cAttribs,
214 const char **paNames)
215{
216 g_paSmlsWinAttribs = pAttribs;
217 g_paSmlsWindows = pWindows;
218 g_cSmlsWindows = cAttribs;
219 g_papszSmlsWinNames = paNames;
220}
221
222static Window g_SmlsShapedWindow = 0;
223static int g_cSmlsShapeRectangles = 0;
224static XRectangle *g_pSmlsShapeRectangles = NULL;
225
226extern "C" XRectangle *XShapeGetRectangles (Display *dpy, Window window,
227 int kind, int *count,
228 int *ordering);
229XRectangle *XShapeGetRectangles (Display *dpy, Window window, int kind,
230 int *count, int *ordering)
231{
232 if ((window != g_SmlsShapedWindow) || (window == 0))
233 return NULL; /* Probably not correct, but works for us. */
234 *count = g_cSmlsShapeRectangles;
235 *ordering = 0;
236 return (XRectangle *)RTMemDup(g_pSmlsShapeRectangles,
237 sizeof(XRectangle)
238 * g_cSmlsShapeRectangles);
239}
240
241static void smlsSetShapeRectangles(Window window, int cRects,
242 XRectangle *pRects)
243{
244 g_SmlsShapedWindow = window;
245 g_cSmlsShapeRectangles = cRects;
246 g_pSmlsShapeRectangles = pRects;
247}
248
249/* This should not be needed in the bits of the code we test. */
250extern "C" int XNextEvent(Display *display, XEvent *event_return);
251int XNextEvent(Display *display, XEvent *event_return)
252{
253 AssertFailedReturn(0);
254}
255
256/* This should not be needed in the bits of the code we test. */
257extern "C" Status XSendEvent(Display *display, Window w, Bool propagate,
258 long event_mask, XEvent *event_send);
259Status XSendEvent(Display *display, Window w, Bool propagate,
260 long event_mask, XEvent *event_send)
261{
262 AssertFailedReturn(0);
263}
264
265/* This should not be needed in the bits of the code we test. */
266extern "C" int XFlush(Display *display);
267int XFlush(Display *display)
268{
269 AssertFailedReturn(0);
270}
271
272/*****************************
273* The actual tests to be run *
274*****************************/
275
276/** The name of the unit test */
277static const char *g_pszTestName = NULL;
278
279/*** Test fixture data and data structures ***/
280
281/** A structure describing a test fixture to be run through. Each fixture
282 * describes the state of the windows visible (and unmapped) on the X server
283 * before and after a particular event is delivered, and the expected
284 * on-screen positions of all interesting visible windows at the end of the
285 * fixture as reported by the code (currently in the order it is likely to
286 * report them in, @todo sort this). We expect that the set of visible
287 * windows will be the same whether we start the code before the event and
288 * handle it or start the code after the event.
289 *
290 * If it is ever needed I could write a small tool to record a fixture on
291 * a live guest, but I will put that off as long as I can.
292 */
293struct SMLSFIXTURE
294{
295 /** The number of windows visible before the event */
296 unsigned cWindowsBefore;
297 /** An array of Window IDs for the visible and unmapped windows before
298 * the event */
299 Window *pahWindowsBefore;
300 /** The window attributes matching the windows in @a paWindowsBefore */
301 XWindowAttributes *paAttribsBefore;
302 /** The window names matching the windows in @a paWindowsBefore */
303 const char **papszNamesBefore;
304 /** The shaped window before the event - we allow at most one of these.
305 * Zero for none. */
306 Window hShapeWindowBefore;
307 /** The number of rectangles in the shaped window before the event. */
308 int cShapeRectsBefore;
309 /** The rectangles in the shaped window before the event */
310 XRectangle *paShapeRectsBefore;
311 /** The number of windows visible after the event */
312 unsigned cWindowsAfter;
313 /** An array of Window IDs for the visible and unmapped windows after
314 * the event */
315 Window *pahWindowsAfter;
316 /** The window attributes matching the windows in @a paWindowsAfter */
317 XWindowAttributes *paAttribsAfter;
318 /** The window names matching the windows in @a paWindowsAfter */
319 const char **papszNamesAfter;
320 /** The shaped window after the event - we allow at most one of these.
321 * Zero for none. */
322 Window hShapeWindowAfter;
323 /** The number of rectangles in the shaped window after the event. */
324 int cShapeRectsAfter;
325 /** The rectangles in the shaped window after the event */
326 XRectangle *paShapeRectsAfter;
327 /** The event to delivered */
328 int x11EventType;
329 /** The windows for which the event in @enmEvent is delivered */
330 Window hEventWindow;
331 /** The number of windows expected to be reported at the end of the
332 * fixture */
333 unsigned cReportedRects;
334 /** The onscreen positions of those windows. */
335 RTRECT *paReportedRects;
336};
337
338/*** Test fixture to test the code against X11 configure (move) events ***/
339
340static Window g_ahWin1[] = { 20 };
341static XWindowAttributes g_aAttrib1Before[] =
342{ { 100, 200, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsViewable }
343};
344static XRectangle g_aRectangle1[] =
345{
346 { 0, 0, 50, 50 },
347 { 50, 50, 150, 250 }
348};
349static XWindowAttributes g_aAttrib1After[] =
350{ { 200, 300, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsViewable }
351};
352static const char *g_apszNames1[] = { "Test Window" };
353
354AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib1Before));
355AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib1After));
356AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_apszNames1));
357
358static RTRECT g_aRects1[] =
359{
360 { 200, 300, 250, 350 },
361 { 250, 350, 400, 600 }
362};
363
364static SMLSFIXTURE g_testMove =
365{
366 RT_ELEMENTS(g_ahWin1),
367 g_ahWin1,
368 g_aAttrib1Before,
369 g_apszNames1,
370 20,
371 RT_ELEMENTS(g_aRectangle1),
372 g_aRectangle1,
373 RT_ELEMENTS(g_ahWin1),
374 g_ahWin1,
375 g_aAttrib1After,
376 g_apszNames1,
377 20,
378 RT_ELEMENTS(g_aRectangle1),
379 g_aRectangle1,
380 ConfigureNotify,
381 20,
382 RT_ELEMENTS(g_aRects1),
383 g_aRects1
384};
385
386/*** Test fixture to test the code against X11 configure (resize) events ***/
387
388static XWindowAttributes g_aAttrib2Before[] =
389{ { 100, 200, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsViewable }
390};
391static XRectangle g_aRectangle2Before[] =
392{
393 { 0, 0, 50, 50 },
394 { 50, 50, 100, 100 }
395};
396
397AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib2Before));
398
399static SMLSFIXTURE g_testResize =
400{
401 RT_ELEMENTS(g_ahWin1),
402 g_ahWin1,
403 g_aAttrib2Before,
404 g_apszNames1,
405 20,
406 RT_ELEMENTS(g_aRectangle2Before),
407 g_aRectangle2Before,
408 RT_ELEMENTS(g_ahWin1),
409 g_ahWin1,
410 g_aAttrib1After,
411 g_apszNames1,
412 20,
413 RT_ELEMENTS(g_aRectangle1),
414 g_aRectangle1,
415 ConfigureNotify,
416 20,
417 RT_ELEMENTS(g_aRects1),
418 g_aRects1
419};
420
421/*** Test fixture to test the code against X11 map events ***/
422
423static XWindowAttributes g_aAttrib3Before[] =
424{ { 200, 300, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsUnmapped }
425};
426
427AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib3Before));
428
429static SMLSFIXTURE g_testMap =
430{
431 RT_ELEMENTS(g_ahWin1),
432 g_ahWin1,
433 g_aAttrib3Before,
434 g_apszNames1,
435 20,
436 RT_ELEMENTS(g_aRectangle1),
437 g_aRectangle1,
438 RT_ELEMENTS(g_ahWin1),
439 g_ahWin1,
440 g_aAttrib1After,
441 g_apszNames1,
442 20,
443 RT_ELEMENTS(g_aRectangle1),
444 g_aRectangle1,
445 MapNotify,
446 20,
447 RT_ELEMENTS(g_aRects1),
448 g_aRects1
449};
450
451/*** Test fixture to test the code against X11 unmap events ***/
452
453static XWindowAttributes g_aAttrib4After[] =
454{ { 100, 200, 300, 400, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsUnmapped }
455};
456
457AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib4After));
458
459static SMLSFIXTURE g_testUnmap =
460{
461 RT_ELEMENTS(g_ahWin1),
462 g_ahWin1,
463 g_aAttrib1Before,
464 g_apszNames1,
465 20,
466 RT_ELEMENTS(g_aRectangle1),
467 g_aRectangle1,
468 RT_ELEMENTS(g_ahWin1),
469 g_ahWin1,
470 g_aAttrib4After,
471 g_apszNames1,
472 20,
473 RT_ELEMENTS(g_aRectangle1),
474 g_aRectangle1,
475 UnmapNotify,
476 20,
477 0,
478 NULL
479};
480
481/*** Test fixture to test the code against X11 shape events ***/
482
483static XRectangle g_aRectangle5Before[] =
484{
485 { 0, 0, 200, 200 }
486};
487
488static SMLSFIXTURE g_testShape =
489{
490 RT_ELEMENTS(g_ahWin1),
491 g_ahWin1,
492 g_aAttrib1After,
493 g_apszNames1,
494 20,
495 RT_ELEMENTS(g_aRectangle5Before),
496 g_aRectangle5Before,
497 RT_ELEMENTS(g_ahWin1),
498 g_ahWin1,
499 g_aAttrib1After,
500 g_apszNames1,
501 20,
502 RT_ELEMENTS(g_aRectangle1),
503 g_aRectangle1,
504 VBoxShapeNotify,
505 20,
506 RT_ELEMENTS(g_aRects1),
507 g_aRects1
508};
509
510/*** And the test code proper ***/
511
512/** Compare two RTRECT structures */
513static bool smlsCompRect(RTRECT *pFirst, RTRECT *pSecond)
514{
515 return ( (pFirst->xLeft == pSecond->xLeft)
516 && (pFirst->yTop == pSecond->yTop)
517 && (pFirst->xRight == pSecond->xRight)
518 && (pFirst->yBottom == pSecond->yBottom));
519}
520
521static void smlsPrintDiffRects(RTRECT *pExp, RTRECT *pGot)
522{
523 RTPrintf(" Expected: %d, %d, %d, %d. Got: %d, %d, %d, %d\n",
524 pExp->xLeft, pExp->yTop, pExp->xRight, pExp->yBottom,
525 pGot->xLeft, pGot->yTop, pGot->xRight, pGot->yBottom);
526}
527
528/** Run through a test fixture */
529static unsigned smlsDoFixture(SMLSFIXTURE *pFixture, const char *pszDesc)
530{
531 VBoxGuestSeamlessX11 subject;
532 unsigned cErrs = 0;
533
534 subject.init(NULL);
535 smlsSetWindowAttributes(pFixture->paAttribsBefore,
536 pFixture->pahWindowsBefore,
537 pFixture->cWindowsBefore,
538 pFixture->papszNamesBefore);
539 smlsSetShapeRectangles(pFixture->hShapeWindowBefore,
540 pFixture->cShapeRectsBefore,
541 pFixture->paShapeRectsBefore);
542 subject.start();
543 smlsSetWindowAttributes(pFixture->paAttribsAfter,
544 pFixture->pahWindowsAfter,
545 pFixture->cWindowsAfter,
546 pFixture->papszNamesAfter);
547 smlsSetShapeRectangles(pFixture->hShapeWindowAfter,
548 pFixture->cShapeRectsAfter,
549 pFixture->paShapeRectsAfter);
550 switch(pFixture->x11EventType)
551 {
552 case ConfigureNotify:
553 subject.doConfigureEvent(pFixture->hEventWindow);
554 break;
555 case MapNotify:
556 subject.doMapEvent(pFixture->hEventWindow);
557 break;
558 case UnmapNotify:
559 subject.doUnmapEvent(pFixture->hEventWindow);
560 break;
561 case VBoxShapeNotify:
562 subject.doShapeEvent(pFixture->hEventWindow);
563 break;
564 default:
565 break;
566 }
567 std::auto_ptr<std::vector<RTRECT> > rects = subject.getRects();
568 if (rects->size() != pFixture->cReportedRects)
569 {
570 RTPrintf("%s: fixture: %s. Wrong number of rectangles reported after processing event (expected %u, got %u).\n",
571 g_pszTestName, pszDesc, pFixture->cReportedRects,
572 (*rects).size());
573 ++cErrs;
574 }
575 else
576 for (unsigned i = 0; i < rects->size(); ++i)
577 if (!smlsCompRect(&(*rects)[i], &pFixture->paReportedRects[i]))
578 {
579 RTPrintf("%s: fixture: %s. Rectangle %u wrong after processing event.\n",
580 g_pszTestName, pszDesc, i);
581 smlsPrintDiffRects(&pFixture->paReportedRects[i],
582 &(*rects)[i]);
583 ++cErrs;
584 break;
585 }
586 subject.stop();
587 subject.start();
588 if (rects->size() != pFixture->cReportedRects)
589 {
590 RTPrintf("%s: fixture: %s. Wrong number of rectangles reported without processing event (expected %u, got %u).\n",
591 g_pszTestName, pszDesc, pFixture->cReportedRects,
592 (*rects).size());
593 ++cErrs;
594 }
595 else
596 for (unsigned i = 0; i < rects->size(); ++i)
597 if (!smlsCompRect(&(*rects)[i], &pFixture->paReportedRects[i]))
598 {
599 RTPrintf("%s: fixture: %s. Rectangle %u wrong without processing event.\n",
600 g_pszTestName, pszDesc, i);
601 smlsPrintDiffRects(&pFixture->paReportedRects[i],
602 &(*rects)[i]);
603 ++cErrs;
604 break;
605 }
606 return cErrs;
607}
608
609int main( int argc, char **argv)
610{
611 RTR3Init();
612 unsigned cErrs = 0;
613 g_pszTestName = RTPathFilename(argv[0]);
614
615 RTPrintf("%s: TESTING\n", g_pszTestName);
616 cErrs += smlsDoFixture(&g_testMove,
617 "ConfigureNotify event (window moved)");
618 // Currently not working
619 cErrs += smlsDoFixture(&g_testResize,
620 "ConfigureNotify event (window resized)");
621 cErrs += smlsDoFixture(&g_testMap, "MapNotify event");
622 cErrs += smlsDoFixture(&g_testUnmap, "UnmapNotify event");
623 cErrs += smlsDoFixture(&g_testShape, "ShapeNotify event");
624 if (cErrs > 0)
625 RTPrintf("%u errors\n", cErrs);
626 return cErrs == 0 ? 0 : 1;
627}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette