VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/testcases/tstClipboardGH-X11.cpp@ 85091

Last change on this file since 85091 was 82922, checked in by vboxsync, 5 years ago

Shared Clipboard/tstClipboardGH-X11: More linking fun required for the testboxes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 KB
Line 
1/* $Id: tstClipboardGH-X11.cpp 82922 2020-01-30 11:41:25Z vboxsync $ */
2/** @file
3 * Shared Clipboard guest/host X11 code test cases.
4 */
5
6/*
7 * Copyright (C) 2011-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <VBox/GuestHost/SharedClipboard.h>
19#include <VBox/GuestHost/SharedClipboard-x11.h>
20#include <VBox/GuestHost/clipboard-helper.h>
21#include <VBox/HostServices/VBoxClipboardSvc.h>
22
23#include <iprt/assert.h>
24#include <iprt/string.h>
25#include <iprt/test.h>
26#include <iprt/utf16.h>
27
28#include <poll.h>
29#include <X11/Xatom.h>
30
31
32/*********************************************************************************************************************************
33* Externals *
34*********************************************************************************************************************************/
35extern SHCLX11FMTTABLE g_aFormats[];
36
37extern void clipUpdateX11Targets(PSHCLX11CTX pCtx, SHCLX11FMTIDX *pTargets, size_t cTargets);
38extern void clipReportEmptyX11CB(PSHCLX11CTX pCtx);
39extern void clipConvertDataFromX11CallbackWorker(void *pClient, void *pvSrc, unsigned cbSrc);
40extern SHCLX11FMTIDX clipGetTextFormatFromTargets(PSHCLX11CTX pCtx, SHCLX11FMTIDX *pTargets, size_t cTargets);
41extern SHCLX11FMT clipRealFormatForX11Format(SHCLX11FMTIDX uFmtIdx);
42extern Atom clipGetAtom(PSHCLX11CTX pCtx, const char *pcszName);
43
44
45/*********************************************************************************************************************************
46* Internal prototypes *
47*********************************************************************************************************************************/
48static SHCLX11FMTIDX tstClipFindX11FormatByAtomText(const char *pcszAtom);
49
50
51/*********************************************************************************************************************************
52* Prototypes, used for testcases by clipboard-x11.cpp *
53*********************************************************************************************************************************/
54void tstRequestTargets(SHCLX11CTX* pCtx);
55void tstClipRequestData(PSHCLX11CTX pCtx, SHCLX11FMTIDX target, void *closure);
56void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data);
57
58
59/*********************************************************************************************************************************
60* Own callback implementations *
61*********************************************************************************************************************************/
62extern DECLCALLBACK(void) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx);
63extern DECLCALLBACK(void) clipConvertX11TargetsCallback(Widget widget, XtPointer pClient,
64 Atom * /* selection */, Atom *atomType,
65 XtPointer pValue, long unsigned int *pcLen,
66 int *piFormat);
67
68
69/*********************************************************************************************************************************
70* Defines *
71*********************************************************************************************************************************/
72#define TESTCASE_WIDGET_ID (Widget)0xffff
73
74
75/* For the purpose of the test case, we just execute the procedure to be
76 * scheduled, as we are running single threaded. */
77void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data)
78{
79 proc(client_data, NULL);
80}
81
82/* The data in the simulated VBox clipboard. */
83static int g_tst_rcDataVBox = VINF_SUCCESS;
84static void *g_tst_pvDataVBox = NULL;
85static uint32_t g_tst_cbDataVBox = 0;
86
87/* Set empty data in the simulated VBox clipboard. */
88static void tstClipEmptyVBox(PSHCLX11CTX pCtx, int retval)
89{
90 g_tst_rcDataVBox = retval;
91 RTMemFree(g_tst_pvDataVBox);
92 g_tst_pvDataVBox = NULL;
93 g_tst_cbDataVBox = 0;
94 ShClX11ReportFormatsToX11(pCtx, 0);
95}
96
97/* Set the data in the simulated VBox clipboard. */
98static int tstClipSetVBoxUtf16(PSHCLX11CTX pCtx, int retval,
99 const char *pcszData, size_t cb)
100{
101 PRTUTF16 pwszData = NULL;
102 size_t cwData = 0;
103 int rc = RTStrToUtf16Ex(pcszData, RTSTR_MAX, &pwszData, 0, &cwData);
104 if (RT_FAILURE(rc))
105 return rc;
106 AssertReturn(cb <= cwData * 2 + 2, VERR_BUFFER_OVERFLOW);
107 void *pv = RTMemDup(pwszData, cb);
108 RTUtf16Free(pwszData);
109 if (pv == NULL)
110 return VERR_NO_MEMORY;
111 if (g_tst_pvDataVBox)
112 RTMemFree(g_tst_pvDataVBox);
113 g_tst_rcDataVBox = retval;
114 g_tst_pvDataVBox = pv;
115 g_tst_cbDataVBox = cb;
116 ShClX11ReportFormatsToX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT);
117 return VINF_SUCCESS;
118}
119
120/* Return the data in the simulated VBox clipboard. */
121DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, uint32_t Format, void **ppv, uint32_t *pcb)
122{
123 RT_NOREF(pCtx, Format);
124 *pcb = g_tst_cbDataVBox;
125 if (g_tst_pvDataVBox != NULL)
126 {
127 void *pv = RTMemDup(g_tst_pvDataVBox, g_tst_cbDataVBox);
128 *ppv = pv;
129 return pv != NULL ? g_tst_rcDataVBox : VERR_NO_MEMORY;
130 }
131 *ppv = NULL;
132 return g_tst_rcDataVBox;
133}
134
135Display *XtDisplay(Widget w) { NOREF(w); return (Display *) 0xffff; }
136
137void XtAppSetExitFlag(XtAppContext app_context) { NOREF(app_context); }
138
139void XtDestroyWidget(Widget w) { NOREF(w); }
140
141XtAppContext XtCreateApplicationContext(void) { return (XtAppContext)0xffff; }
142
143void XtDestroyApplicationContext(XtAppContext app_context) { NOREF(app_context); }
144
145void XtToolkitInitialize(void) {}
146
147Boolean XtToolkitThreadInitialize(void) { return True; }
148
149Display *XtOpenDisplay(XtAppContext app_context,
150 _Xconst _XtString display_string,
151 _Xconst _XtString application_name,
152 _Xconst _XtString application_class,
153 XrmOptionDescRec *options, Cardinal num_options,
154 int *argc, char **argv)
155{
156 RT_NOREF8(app_context, display_string, application_name, application_class, options, num_options, argc, argv);
157 return (Display *)0xffff;
158}
159
160Widget XtVaAppCreateShell(_Xconst _XtString application_name, _Xconst _XtString application_class,
161 WidgetClass widget_class, Display *display, ...)
162{
163 RT_NOREF(application_name, application_class, widget_class, display);
164 return TESTCASE_WIDGET_ID;
165}
166
167void XtSetMappedWhenManaged(Widget widget, _XtBoolean mapped_when_managed) { RT_NOREF(widget, mapped_when_managed); }
168
169void XtRealizeWidget(Widget widget) { NOREF(widget); }
170
171XtInputId XtAppAddInput(XtAppContext app_context, int source, XtPointer condition, XtInputCallbackProc proc, XtPointer closure)
172{
173 RT_NOREF(app_context, source, condition, proc, closure);
174 return 0xffff;
175}
176
177/* Atoms we need other than the formats we support. */
178static const char *g_tst_apszSupAtoms[] =
179{
180 "PRIMARY", "CLIPBOARD", "TARGETS", "MULTIPLE", "TIMESTAMP"
181};
182
183/* This just looks for the atom names in a couple of tables and returns an
184 * index with an offset added. */
185Atom XInternAtom(Display *, const char *pcsz, int)
186{
187 Atom atom = 0;
188 unsigned i = 0;
189 while (g_aFormats[i].pcszAtom)
190 {
191 if (!strcmp(pcsz, g_aFormats[i].pcszAtom))
192 atom = (Atom) (i + 0x1000);
193 ++i;
194 }
195 for (i = 0; i < RT_ELEMENTS(g_tst_apszSupAtoms); ++i)
196 if (!strcmp(pcsz, g_tst_apszSupAtoms[i]))
197 atom = (Atom) (i + 0x2000);
198 Assert(atom); /* Have we missed any atoms? */
199 return atom;
200}
201
202/* Take a request for the targets we are currently offering. */
203static SHCLX11FMTIDX g_tst_aSelTargetsIdx[10] = { 0 };
204static size_t g_tst_cTargets = 0;
205
206void tstRequestTargets(SHCLX11CTX* pCtx)
207{
208 clipUpdateX11Targets(pCtx, g_tst_aSelTargetsIdx, g_tst_cTargets);
209}
210
211/* The current values of the X selection, which will be returned to the
212 * XtGetSelectionValue callback. */
213static Atom g_tst_atmSelType = 0;
214static const void *g_tst_pSelData = NULL;
215static unsigned long g_tst_cSelData = 0;
216static int g_tst_selFormat = 0;
217
218void tstClipRequestData(PSHCLX11CTX pCtx, SHCLX11FMTIDX target, void *closure)
219{
220 RT_NOREF(pCtx);
221 unsigned long count = 0;
222 int format = 0;
223 if (target != g_tst_aSelTargetsIdx[0])
224 {
225 clipConvertDataFromX11CallbackWorker(closure, NULL, 0); /* Could not convert to target. */
226 return;
227 }
228 void *pValue = NULL;
229 pValue = g_tst_pSelData ? RTMemDup(g_tst_pSelData, g_tst_cSelData) : NULL;
230 count = g_tst_pSelData ? g_tst_cSelData : 0;
231 format = g_tst_selFormat;
232 if (!pValue)
233 {
234 count = 0;
235 format = 0;
236 }
237 clipConvertDataFromX11CallbackWorker(closure, pValue, count * format / 8);
238 if (pValue)
239 RTMemFree(pValue);
240}
241
242/* The formats currently on offer from X11 via the shared clipboard. */
243static uint32_t g_tst_uX11Formats = 0;
244
245DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, SHCLFORMATS Formats)
246{
247 RT_NOREF(pCtx);
248 g_tst_uX11Formats = Formats;
249}
250
251static uint32_t tstClipQueryFormats(void)
252{
253 return g_tst_uX11Formats;
254}
255
256static void tstClipInvalidateFormats(void)
257{
258 g_tst_uX11Formats = ~0;
259}
260
261/* Does our clipboard code currently own the selection? */
262static bool g_tst_fOwnsSel = false;
263/* The procedure that is called when we should convert the selection to a
264 * given format. */
265static XtConvertSelectionProc g_tst_pfnSelConvert = NULL;
266/* The procedure which is called when we lose the selection. */
267static XtLoseSelectionProc g_tst_pfnSelLose = NULL;
268/* The procedure which is called when the selection transfer has completed. */
269static XtSelectionDoneProc g_tst_pfnSelDone = NULL;
270
271Boolean XtOwnSelection(Widget widget, Atom selection, Time time,
272 XtConvertSelectionProc convert,
273 XtLoseSelectionProc lose,
274 XtSelectionDoneProc done)
275{
276 RT_NOREF(widget, time);
277 if (selection != XInternAtom(NULL, "CLIPBOARD", 0))
278 return True; /* We don't really care about this. */
279 g_tst_fOwnsSel = true; /* Always succeed. */
280 g_tst_pfnSelConvert = convert;
281 g_tst_pfnSelLose = lose;
282 g_tst_pfnSelDone = done;
283 return True;
284}
285
286void XtDisownSelection(Widget widget, Atom selection, Time time)
287{
288 RT_NOREF(widget, time, selection);
289 g_tst_fOwnsSel = false;
290 g_tst_pfnSelConvert = NULL;
291 g_tst_pfnSelLose = NULL;
292 g_tst_pfnSelDone = NULL;
293}
294
295/* Request the shared clipboard to convert its data to a given format. */
296static bool tstClipConvertSelection(const char *pcszTarget, Atom *type,
297 XtPointer *value, unsigned long *length,
298 int *format)
299{
300 Atom target = XInternAtom(NULL, pcszTarget, 0);
301 if (target == 0)
302 return false;
303 /* Initialise all return values in case we make a quick exit. */
304 *type = XA_STRING;
305 *value = NULL;
306 *length = 0;
307 *format = 0;
308 if (!g_tst_fOwnsSel)
309 return false;
310 if (!g_tst_pfnSelConvert)
311 return false;
312 Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0);
313 if (!g_tst_pfnSelConvert(TESTCASE_WIDGET_ID, &clipAtom, &target, type,
314 value, length, format))
315 return false;
316 if (g_tst_pfnSelDone)
317 g_tst_pfnSelDone(TESTCASE_WIDGET_ID, &clipAtom, &target);
318 return true;
319}
320
321/* Set the current X selection data */
322static void tstClipSetSelectionValues(const char *pcszTarget, Atom type,
323 const void *data,
324 unsigned long count, int format)
325{
326 Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0);
327 g_tst_aSelTargetsIdx[0] = tstClipFindX11FormatByAtomText(pcszTarget);
328 g_tst_cTargets = 1;
329 g_tst_atmSelType = type;
330 g_tst_pSelData = data;
331 g_tst_cSelData = count;
332 g_tst_selFormat = format;
333 if (g_tst_pfnSelLose)
334 g_tst_pfnSelLose(TESTCASE_WIDGET_ID, &clipAtom);
335 g_tst_fOwnsSel = false;
336}
337
338static void tstClipSendTargetUpdate(PSHCLX11CTX pCtx)
339{
340 clipQueryX11FormatsCallback(pCtx);
341}
342
343/* Configure if and how the X11 TARGETS clipboard target will fail. */
344static void tstClipSetTargetsFailure(void)
345{
346 g_tst_cTargets = 0;
347}
348
349char *XtMalloc(Cardinal size)
350{
351 return (char *) RTMemAlloc(size);
352}
353
354void XtFree(char *ptr)
355{
356 RTMemFree((void *)ptr);
357}
358
359char *XGetAtomName(Display *display, Atom atom)
360{
361 RT_NOREF(display);
362 const char *pcszName = NULL;
363 if (atom < 0x1000)
364 return NULL;
365 if (0x1000 <= atom && atom < 0x2000)
366 {
367 unsigned index = atom - 0x1000;
368 pcszName = g_aFormats[index].pcszAtom;
369 }
370 else
371 {
372 unsigned index = atom - 0x2000;
373 AssertReturn(index < RT_ELEMENTS(g_tst_apszSupAtoms), NULL);
374 pcszName = g_tst_apszSupAtoms[index];
375 }
376 return (char *)RTMemDup(pcszName, sizeof(pcszName) + 1);
377}
378
379int XFree(void *data)
380{
381 RTMemFree(data);
382 return 0;
383}
384
385void XFreeStringList(char **list)
386{
387 if (list)
388 RTMemFree(*list);
389 RTMemFree(list);
390}
391
392#define TESTCASE_MAX_BUF_SIZE 256
393
394static int g_tst_rcCompleted = VINF_SUCCESS;
395static int g_tst_cbCompleted = 0;
396static CLIPREADCBREQ *g_tst_pCompletedReq = NULL;
397static char g_tst_abCompletedBuf[TESTCASE_MAX_BUF_SIZE];
398
399void ShClX11RequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
400{
401 RT_NOREF(pCtx);
402 if (cb <= TESTCASE_MAX_BUF_SIZE)
403 {
404 g_tst_rcCompleted = rc;
405 if (cb != 0)
406 memcpy(g_tst_abCompletedBuf, pv, cb);
407 }
408 else
409 g_tst_rcCompleted = VERR_BUFFER_OVERFLOW;
410 g_tst_cbCompleted = cb;
411 g_tst_pCompletedReq = pReq;
412}
413
414/**
415 * Looks up the X11 format matching a given X11 atom text.
416 *
417 * @returns the format on success, NIL_CLIPX11FORMAT on failure
418 * @param pcszAtom Atom text to look up format for.
419 */
420static SHCLX11FMTIDX tstClipFindX11FormatByAtomText(const char *pcszAtom)
421{
422 unsigned i = 0;
423 while (g_aFormats[i].pcszAtom)
424 {
425 if (!strcmp(g_aFormats[i].pcszAtom, pcszAtom))
426 return i;
427 ++i;
428 }
429 return NIL_CLIPX11FORMAT;
430}
431
432static bool tstClipTextFormatConversion(PSHCLX11CTX pCtx)
433{
434 bool fSuccess = true;
435 SHCLX11FMTIDX targets[2];
436 SHCLX11FMTIDX x11Format;
437 targets[0] = tstClipFindX11FormatByAtomText("text/plain");
438 targets[1] = tstClipFindX11FormatByAtomText("image/bmp");
439 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
440 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_TEXT)
441 fSuccess = false;
442 targets[0] = tstClipFindX11FormatByAtomText("UTF8_STRING");
443 targets[1] = tstClipFindX11FormatByAtomText("text/plain");
444 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
445 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_UTF8)
446 fSuccess = false;
447 return fSuccess;
448}
449
450static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, CLIPREADCBREQ **ppReq)
451{
452 *prc = g_tst_rcCompleted;
453 *ppc = g_tst_abCompletedBuf;
454 *pcb = g_tst_cbCompleted;
455 *ppReq = g_tst_pCompletedReq;
456}
457
458static void tstStringFromX11(RTTEST hTest, PSHCLX11CTX pCtx,
459 const char *pcszExp, int rcExp)
460{
461 bool retval = true;
462 tstClipSendTargetUpdate(pCtx);
463 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
464 {
465 RTTestFailed(hTest, "Wrong targets reported: %02X\n", tstClipQueryFormats());
466 }
467 else
468 {
469 char *pc;
470 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
471 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
472 int rc = VINF_SUCCESS;
473 uint32_t cbActual = 0;
474 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
475 if (rc != rcExp)
476 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",
477 rcExp, rc);
478 else if (pReqRet != pReq)
479 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",
480 pReq, pReqRet);
481 else if (RT_FAILURE(rcExp))
482 retval = true;
483 else
484 {
485 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
486 RTUTF16 *pwcExp = wcExp;
487 size_t cwc = 0;
488 rc = RTStrToUtf16Ex(pcszExp, RTSTR_MAX, &pwcExp,
489 RT_ELEMENTS(wcExp), &cwc);
490 size_t cbExp = cwc * 2 + 2;
491 AssertRC(rc);
492 if (RT_SUCCESS(rc))
493 {
494 if (cbActual != cbExp)
495 {
496 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",
497 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,
498 pcszExp, cbExp);
499 }
500 else
501 {
502 if (memcmp(pc, wcExp, cbExp) == 0)
503 retval = true;
504 else
505 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",
506 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);
507 }
508 }
509 }
510 }
511 if (!retval)
512 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",
513 pcszExp, rcExp);
514}
515
516static void tstLatin1FromX11(RTTEST hTest, PSHCLX11CTX pCtx,
517 const char *pcszExp, int rcExp)
518{
519 bool retval = false;
520 tstClipSendTargetUpdate(pCtx);
521 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
522 RTTestFailed(hTest, "Wrong targets reported: %02X\n",
523 tstClipQueryFormats());
524 else
525 {
526 char *pc;
527 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
528 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
529 int rc = VINF_SUCCESS;
530 uint32_t cbActual = 0;
531 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
532 if (rc != rcExp)
533 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",
534 rcExp, rc);
535 else if (pReqRet != pReq)
536 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",
537 pReq, pReqRet);
538 else if (RT_FAILURE(rcExp))
539 retval = true;
540 else
541 {
542 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
543 //RTUTF16 *pwcExp = wcExp; - unused
544 size_t cwc;
545 for (cwc = 0; cwc == 0 || pcszExp[cwc - 1] != '\0'; ++cwc)
546 wcExp[cwc] = pcszExp[cwc];
547 size_t cbExp = cwc * 2;
548 if (cbActual != cbExp)
549 {
550 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",
551 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,
552 pcszExp, cbExp);
553 }
554 else
555 {
556 if (memcmp(pc, wcExp, cbExp) == 0)
557 retval = true;
558 else
559 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",
560 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);
561 }
562 }
563 }
564 if (!retval)
565 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",
566 pcszExp, rcExp);
567}
568
569static void tstStringFromVBox(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget, Atom typeExp, const char *valueExp)
570{
571 RT_NOREF(pCtx);
572 bool retval = false;
573 Atom type;
574 XtPointer value = NULL;
575 unsigned long length;
576 int format;
577 size_t lenExp = strlen(valueExp);
578 if (tstClipConvertSelection(pcszTarget, &type, &value, &length, &format))
579 {
580 if ( type != typeExp
581 || length != lenExp
582 || format != 8
583 || memcmp((const void *) value, (const void *)valueExp,
584 lenExp))
585 {
586 RTTestFailed(hTest, "Bad data: type %d, (expected %d), length %u, (%u), format %d (%d), value \"%.*s\" (\"%.*s\")\n",
587 type, typeExp, length, lenExp, format, 8,
588 RT_MIN(length, 20), value, RT_MIN(lenExp, 20), valueExp);
589 }
590 else
591 retval = true;
592 }
593 else
594 RTTestFailed(hTest, "Conversion failed\n");
595 XtFree((char *)value);
596 if (!retval)
597 RTTestFailureDetails(hTest, "Conversion to %s, expected \"%s\"\n",
598 pcszTarget, valueExp);
599}
600
601static void tstNoX11(PSHCLX11CTX pCtx, const char *pcszTestCtx)
602{
603 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq;
604 int rc = ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
605 RTTESTI_CHECK_MSG(rc == VERR_NO_DATA, ("context: %s\n", pcszTestCtx));
606}
607
608static void tstStringFromVBoxFailed(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget)
609{
610 RT_NOREF(pCtx);
611 Atom type;
612 XtPointer value = NULL;
613 unsigned long length;
614 int format;
615 RTTEST_CHECK_MSG(hTest, !tstClipConvertSelection(pcszTarget, &type, &value,
616 &length, &format),
617 (hTest, "Conversion to target %s, should have failed but didn't, returned type %d, length %u, format %d, value \"%.*s\"\n",
618 pcszTarget, type, length, format, RT_MIN(length, 20),
619 value));
620 XtFree((char *)value);
621}
622
623static void tstNoSelectionOwnership(PSHCLX11CTX pCtx, const char *pcszTestCtx)
624{
625 RT_NOREF(pCtx);
626 RTTESTI_CHECK_MSG(!g_tst_fOwnsSel, ("context: %s\n", pcszTestCtx));
627}
628
629static void tstBadFormatRequestFromHost(RTTEST hTest, PSHCLX11CTX pCtx)
630{
631 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
632 sizeof("hello world"), 8);
633 tstClipSendTargetUpdate(pCtx);
634 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
635 RTTestFailed(hTest, "Wrong targets reported: %02X\n",
636 tstClipQueryFormats());
637 else
638 {
639 char *pc;
640 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
641 ShClX11ReadDataFromX11(pCtx, 0xF000 /* vboxFormat */, pReq); /* Bad format. */
642 int rc = VINF_SUCCESS;
643 uint32_t cbActual = 0;
644 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
645 if (rc != VERR_NOT_IMPLEMENTED)
646 RTTestFailed(hTest, "Wrong return code, expected VERR_NOT_IMPLEMENTED, got %Rrc\n",
647 rc);
648 tstClipSetSelectionValues("", XA_STRING, "", sizeof(""), 8);
649 tstClipSendTargetUpdate(pCtx);
650 if (tstClipQueryFormats() == VBOX_SHCL_FMT_UNICODETEXT)
651 RTTestFailed(hTest, "Failed to report targets after bad host request.\n");
652 }
653}
654
655int main()
656{
657 /*
658 * Init the runtime, test and say hello.
659 */
660 RTTEST hTest;
661 int rc = RTTestInitAndCreate("tstClipboardGH-X11", &hTest);
662 if (rc)
663 return rc;
664 RTTestBanner(hTest);
665
666 /*
667 * Run the tests.
668 */
669 SHCLX11CTX X11Ctx;
670 rc = ShClX11Init(&X11Ctx, NULL, false);
671 AssertRCReturn(rc, 1);
672 char *pc;
673 uint32_t cbActual;
674 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
675 rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);
676 AssertRCReturn(rc, 1);
677
678 /* UTF-8 from X11 */
679 RTTestSub(hTest, "reading UTF-8 from X11");
680 /* Simple test */
681 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
682 sizeof("hello world"), 8);
683 tstStringFromX11(hTest, &X11Ctx, "hello world", VINF_SUCCESS);
684 /* With an embedded carriage return */
685 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,
686 "hello\nworld", sizeof("hello\nworld"), 8);
687 tstStringFromX11(hTest, &X11Ctx, "hello\r\nworld", VINF_SUCCESS);
688 /* With an embedded CRLF */
689 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,
690 "hello\r\nworld", sizeof("hello\r\nworld"), 8);
691 tstStringFromX11(hTest, &X11Ctx, "hello\r\r\nworld", VINF_SUCCESS);
692 /* With an embedded LFCR */
693 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,
694 "hello\n\rworld", sizeof("hello\n\rworld"), 8);
695 tstStringFromX11(hTest, &X11Ctx, "hello\r\n\rworld", VINF_SUCCESS);
696 /* An empty string */
697 tstClipSetSelectionValues("text/plain;charset=utf-8", XA_STRING, "",
698 sizeof(""), 8);
699 tstStringFromX11(hTest, &X11Ctx, "", VINF_SUCCESS);
700 /* With an embedded UTF-8 character. */
701 tstClipSetSelectionValues("STRING", XA_STRING,
702 "100\xE2\x82\xAC" /* 100 Euro */,
703 sizeof("100\xE2\x82\xAC"), 8);
704 tstStringFromX11(hTest, &X11Ctx, "100\xE2\x82\xAC", VINF_SUCCESS);
705 /* A non-zero-terminated string */
706 tstClipSetSelectionValues("TEXT", XA_STRING,
707 "hello world", sizeof("hello world") - 1, 8);
708 tstStringFromX11(hTest, &X11Ctx, "hello world", VINF_SUCCESS);
709
710 /* Latin1 from X11 */
711 RTTestSub(hTest, "reading Latin1 from X11");
712 /* Simple test */
713 tstClipSetSelectionValues("STRING", XA_STRING, "Georges Dupr\xEA",
714 sizeof("Georges Dupr\xEA"), 8);
715 tstLatin1FromX11(hTest, &X11Ctx, "Georges Dupr\xEA", VINF_SUCCESS);
716 /* With an embedded carriage return */
717 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\nDupr\xEA",
718 sizeof("Georges\nDupr\xEA"), 8);
719 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\nDupr\xEA", VINF_SUCCESS);
720 /* With an embedded CRLF */
721 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\r\nDupr\xEA",
722 sizeof("Georges\r\nDupr\xEA"), 8);
723 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\r\nDupr\xEA", VINF_SUCCESS);
724 /* With an embedded LFCR */
725 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\n\rDupr\xEA",
726 sizeof("Georges\n\rDupr\xEA"), 8);
727 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\n\rDupr\xEA", VINF_SUCCESS);
728 /* A non-zero-terminated string */
729 tstClipSetSelectionValues("text/plain", XA_STRING,
730 "Georges Dupr\xEA!",
731 sizeof("Georges Dupr\xEA!") - 1, 8);
732 tstLatin1FromX11(hTest, &X11Ctx, "Georges Dupr\xEA!", VINF_SUCCESS);
733
734 /*
735 * Unknown X11 format
736 */
737 RTTestSub(hTest, "handling of an unknown X11 format");
738 tstClipInvalidateFormats();
739 tstClipSetSelectionValues("CLIPBOARD", XA_STRING, "Test",
740 sizeof("Test"), 8);
741 tstClipSendTargetUpdate(&X11Ctx);
742 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,
743 (hTest, "Failed to send a format update notification\n"));
744
745 /*
746 * Timeout from X11
747 */
748 RTTestSub(hTest, "X11 timeout");
749 tstClipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, NULL,0, 8);
750 tstStringFromX11(hTest, &X11Ctx, "", VERR_NO_DATA);
751
752 /*
753 * No data in X11 clipboard
754 */
755 RTTestSub(hTest, "a data request from an empty X11 clipboard");
756 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, NULL,
757 0, 8);
758 ShClX11ReadDataFromX11(&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
759 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
760 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,
761 (hTest, "Returned %Rrc instead of VERR_NO_DATA\n",
762 rc));
763 RTTEST_CHECK_MSG(hTest, pReqRet == pReq,
764 (hTest, "Wrong returned request data, expected %p, got %p\n",
765 pReq, pReqRet));
766
767 /*
768 * Ensure that VBox is notified when we return the CB to X11
769 */
770 RTTestSub(hTest, "notification of switch to X11 clipboard");
771 tstClipInvalidateFormats();
772 clipReportEmptyX11CB(&X11Ctx);
773 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,
774 (hTest, "Failed to send a format update (release) notification\n"));
775
776 /*
777 * Request for an invalid VBox format from X11
778 */
779 RTTestSub(hTest, "a request for an invalid VBox format from X11");
780 /* Testing for 0xffff will go into handling VBOX_SHCL_FMT_UNICODETEXT, where we don't have
781 * have any data at the moment so far, so this will return VERR_NO_DATA. */
782 ShClX11ReadDataFromX11(&X11Ctx, 0xffff /* vboxFormat */, pReq);
783 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
784 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,
785 (hTest, "Returned %Rrc instead of VERR_NO_DATA\n",
786 rc));
787 RTTEST_CHECK_MSG(hTest, pReqRet == pReq,
788 (hTest, "Wrong returned request data, expected %p, got %p\n",
789 pReq, pReqRet));
790
791 /*
792 * Targets failure from X11
793 */
794 RTTestSub(hTest, "X11 targets conversion failure");
795 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
796 sizeof("hello world"), 8);
797 tstClipSetTargetsFailure();
798 Atom atom = XA_STRING;
799 long unsigned int cLen = 0;
800 int format = 8;
801 clipConvertX11TargetsCallback(NULL, (XtPointer) &X11Ctx, NULL, &atom, NULL, &cLen,
802 &format);
803 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,
804 (hTest, "Wrong targets reported: %02X\n",
805 tstClipQueryFormats()));
806
807 /*
808 * X11 text format conversion
809 */
810 RTTestSub(hTest, "handling of X11 selection targets");
811 RTTEST_CHECK_MSG(hTest, tstClipTextFormatConversion(&X11Ctx),
812 (hTest, "failed to select the right X11 text formats\n"));
813
814 /*
815 * UTF-8 from VBox
816 */
817 RTTestSub(hTest, "reading UTF-8 from VBox");
818 /* Simple test */
819 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
820 sizeof("hello world") * 2);
821 tstStringFromVBox(hTest, &X11Ctx, "UTF8_STRING",
822 clipGetAtom(&X11Ctx, "UTF8_STRING"), "hello world");
823 /* With an embedded carriage return */
824 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\nworld",
825 sizeof("hello\r\nworld") * 2);
826 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",
827 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),
828 "hello\nworld");
829 /* With an embedded CRCRLF */
830 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\r\nworld",
831 sizeof("hello\r\r\nworld") * 2);
832 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",
833 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),
834 "hello\r\nworld");
835 /* With an embedded CRLFCR */
836 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\n\rworld",
837 sizeof("hello\r\n\rworld") * 2);
838 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",
839 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),
840 "hello\n\rworld");
841 /* An empty string */
842 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);
843 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=utf-8",
844 clipGetAtom(&X11Ctx, "text/plain;charset=utf-8"), "");
845 /* With an embedded UTF-8 character. */
846 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */,
847 10);
848 tstStringFromVBox(hTest, &X11Ctx, "STRING",
849 clipGetAtom(&X11Ctx, "STRING"), "100\xE2\x82\xAC");
850 /* A non-zero-terminated string */
851 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
852 sizeof("hello world") * 2 - 2);
853 tstStringFromVBox(hTest, &X11Ctx, "TEXT", clipGetAtom(&X11Ctx, "TEXT"),
854 "hello world");
855
856 /*
857 * Timeout from VBox
858 */
859 RTTestSub(hTest, "reading from VBox with timeout");
860 tstClipEmptyVBox(&X11Ctx, VERR_TIMEOUT);
861 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");
862
863 /*
864 * No data in VBox clipboard
865 */
866 RTTestSub(hTest, "an empty VBox clipboard");
867 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
868 tstClipEmptyVBox(&X11Ctx, VINF_SUCCESS);
869 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,
870 (hTest, "VBox grabbed the clipboard with no data and we ignored it\n"));
871 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");
872
873 /*
874 * An unknown VBox format
875 */
876 RTTestSub(hTest, "reading an unknown VBox format");
877 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
878 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);
879 ShClX11ReportFormatsToX11(&X11Ctx, 0xa0000);
880 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,
881 (hTest, "VBox grabbed the clipboard with unknown data and we ignored it\n"));
882 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");
883
884 /*
885 * VBox requests a bad format
886 */
887 RTTestSub(hTest, "recovery from a bad format request");
888 tstBadFormatRequestFromHost(hTest, &X11Ctx);
889
890 rc = ShClX11ThreadStop(&X11Ctx);
891 AssertRCReturn(rc, 1);
892 ShClX11Destroy(&X11Ctx);
893
894 /*
895 * Headless clipboard tests
896 */
897 rc = ShClX11Init(&X11Ctx, NULL, true);
898 AssertRCReturn(rc, 1);
899 rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);
900 AssertRCReturn(rc, 1);
901
902 /* Read from X11 */
903 RTTestSub(hTest, "reading from X11, headless clipboard");
904 /* Simple test */
905 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "",
906 sizeof("") * 2);
907 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
908 sizeof("hello world"), 8);
909 tstNoX11(&X11Ctx, "reading from X11, headless clipboard");
910
911 /* Read from VBox */
912 RTTestSub(hTest, "reading from VBox, headless clipboard");
913 /* Simple test */
914 tstClipEmptyVBox(&X11Ctx, VERR_WRONG_ORDER);
915 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
916 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
917 sizeof("hello world") * 2);
918 tstNoSelectionOwnership(&X11Ctx, "reading from VBox, headless clipboard");
919
920 rc = ShClX11ThreadStop(&X11Ctx);
921 AssertRCReturn(rc, 1);
922
923 ShClX11Destroy(&X11Ctx);
924
925 return RTTestSummaryAndDestroy(hTest);
926}
927
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