VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardGH-X11.cpp@ 91999

Last change on this file since 91999 was 87566, checked in by vboxsync, 4 years ago

Shared Clipboard: doxygen fixes for unnecessary @copydoc in definitions and duplicate @param docs. (probably bugref:9437)

  • 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 87566 2021-02-03 13:48:48Z 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 clipReportEmpty(PSHCLX11CTX pCtx);
39extern void clipConvertDataFromX11Worker(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);
43extern void clipQueryX11Formats(PSHCLX11CTX pCtx);
44extern size_t clipReportMaxX11Formats(void);
45
46
47/*********************************************************************************************************************************
48* Internal prototypes *
49*********************************************************************************************************************************/
50static SHCLX11FMTIDX tstClipFindX11FormatByAtomText(const char *pcszAtom);
51
52
53/*********************************************************************************************************************************
54* Prototypes, used for testcases by clipboard-x11.cpp *
55*********************************************************************************************************************************/
56void tstRequestTargets(SHCLX11CTX* pCtx);
57void tstClipRequestData(PSHCLX11CTX pCtx, SHCLX11FMTIDX target, void *closure);
58void tstThreadScheduleCall(void (*proc)(void *, void *), void *client_data);
59
60
61/*********************************************************************************************************************************
62* Own callback implementations *
63*********************************************************************************************************************************/
64extern DECLCALLBACK(void) clipConvertX11TargetsCallback(Widget widget, XtPointer pClient,
65 Atom * /* selection */, Atom *atomType,
66 XtPointer pValue, long unsigned int *pcLen,
67 int *piFormat);
68
69
70/*********************************************************************************************************************************
71* Defines *
72*********************************************************************************************************************************/
73#define TESTCASE_WIDGET_ID (Widget)0xffff
74
75
76/* For the purpose of the test case, we just execute the procedure to be
77 * scheduled, as we are running single threaded. */
78void tstThreadScheduleCall(void (*proc)(void *, void *), void *client_data)
79{
80 proc(client_data, NULL);
81}
82
83/* The data in the simulated VBox clipboard. */
84static int g_tst_rcDataVBox = VINF_SUCCESS;
85static void *g_tst_pvDataVBox = NULL;
86static uint32_t g_tst_cbDataVBox = 0;
87
88/* Set empty data in the simulated VBox clipboard. */
89static void tstClipEmptyVBox(PSHCLX11CTX pCtx, int retval)
90{
91 g_tst_rcDataVBox = retval;
92 RTMemFree(g_tst_pvDataVBox);
93 g_tst_pvDataVBox = NULL;
94 g_tst_cbDataVBox = 0;
95 ShClX11ReportFormatsToX11(pCtx, 0);
96}
97
98/* Set the data in the simulated VBox clipboard. */
99static int tstClipSetVBoxUtf16(PSHCLX11CTX pCtx, int retval,
100 const char *pcszData, size_t cb)
101{
102 PRTUTF16 pwszData = NULL;
103 size_t cwData = 0;
104 int rc = RTStrToUtf16Ex(pcszData, RTSTR_MAX, &pwszData, 0, &cwData);
105 if (RT_FAILURE(rc))
106 return rc;
107 AssertReturn(cb <= cwData * 2 + 2, VERR_BUFFER_OVERFLOW);
108 void *pv = RTMemDup(pwszData, cb);
109 RTUtf16Free(pwszData);
110 if (pv == NULL)
111 return VERR_NO_MEMORY;
112 if (g_tst_pvDataVBox)
113 RTMemFree(g_tst_pvDataVBox);
114 g_tst_rcDataVBox = retval;
115 g_tst_pvDataVBox = pv;
116 g_tst_cbDataVBox = cb;
117 ShClX11ReportFormatsToX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT);
118 return VINF_SUCCESS;
119}
120
121DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, uint32_t uFmt, void **ppv, uint32_t *pcb)
122{
123 RT_NOREF(pCtx, uFmt);
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 size_t const cFormats = clipReportMaxX11Formats();
189 size_t i;
190 for (i = 0; i < cFormats; ++i)
191 {
192 if (!strcmp(pcsz, g_aFormats[i].pcszAtom))
193 atom = (Atom) (i + 0x1000);
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 clipConvertDataFromX11Worker(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 clipConvertDataFromX11Worker(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 fFormats)
246{
247 RT_NOREF(pCtx);
248 g_tst_uX11Formats = fFormats;
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 clipQueryX11Formats(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 AssertReturn(index < clipReportMaxX11Formats(), NULL);
369 pcszName = g_aFormats[index].pcszAtom;
370 }
371 else
372 {
373 unsigned index = atom - 0x2000;
374 AssertReturn(index < RT_ELEMENTS(g_tst_apszSupAtoms), NULL);
375 pcszName = g_tst_apszSupAtoms[index];
376 }
377 return (char *)RTMemDup(pcszName, sizeof(pcszName) + 1);
378}
379
380int XFree(void *data)
381{
382 RTMemFree(data);
383 return 0;
384}
385
386void XFreeStringList(char **list)
387{
388 if (list)
389 RTMemFree(*list);
390 RTMemFree(list);
391}
392
393#define TESTCASE_MAX_BUF_SIZE 256
394
395static int g_tst_rcCompleted = VINF_SUCCESS;
396static int g_tst_cbCompleted = 0;
397static CLIPREADCBREQ *g_tst_pCompletedReq = NULL;
398static char g_tst_abCompletedBuf[TESTCASE_MAX_BUF_SIZE];
399
400DECLCALLBACK(void) ShClX11RequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rcCompletion,
401 CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
402{
403 RT_NOREF(pCtx);
404 if (cb <= TESTCASE_MAX_BUF_SIZE)
405 {
406 g_tst_rcCompleted = rcCompletion;
407 if (cb != 0)
408 memcpy(g_tst_abCompletedBuf, pv, cb);
409 }
410 else
411 g_tst_rcCompleted = VERR_BUFFER_OVERFLOW;
412 g_tst_cbCompleted = cb;
413 g_tst_pCompletedReq = pReq;
414}
415
416/**
417 * Looks up the X11 format matching a given X11 atom text.
418 *
419 * @returns the format on success, NIL_CLIPX11FORMAT on failure
420 * @param pcszAtom Atom text to look up format for.
421 */
422static SHCLX11FMTIDX tstClipFindX11FormatByAtomText(const char *pcszAtom)
423{
424 const size_t j = clipReportMaxX11Formats();
425
426 for (unsigned i = 0; i < j; ++i)
427 {
428 if (!strcmp(g_aFormats[i].pcszAtom, pcszAtom))
429 return i;
430 }
431 return NIL_CLIPX11FORMAT;
432}
433
434static bool tstClipTextFormatConversion(PSHCLX11CTX pCtx)
435{
436 bool fSuccess = true;
437 SHCLX11FMTIDX targets[2];
438 SHCLX11FMTIDX x11Format;
439 targets[0] = tstClipFindX11FormatByAtomText("text/plain");
440 targets[1] = tstClipFindX11FormatByAtomText("image/bmp");
441 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
442 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_TEXT)
443 fSuccess = false;
444 targets[0] = tstClipFindX11FormatByAtomText("UTF8_STRING");
445 targets[1] = tstClipFindX11FormatByAtomText("text/plain");
446 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
447 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_UTF8)
448 fSuccess = false;
449 return fSuccess;
450}
451
452static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, CLIPREADCBREQ **ppReq)
453{
454 *prc = g_tst_rcCompleted;
455 *ppc = g_tst_abCompletedBuf;
456 *pcb = g_tst_cbCompleted;
457 *ppReq = g_tst_pCompletedReq;
458}
459
460static void tstStringFromX11(RTTEST hTest, PSHCLX11CTX pCtx,
461 const char *pcszExp, int rcExp)
462{
463 bool retval = true;
464 tstClipSendTargetUpdate(pCtx);
465 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
466 {
467 RTTestFailed(hTest, "Wrong targets reported: %02X\n", tstClipQueryFormats());
468 }
469 else
470 {
471 char *pc;
472 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
473 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
474 int rc = VINF_SUCCESS;
475 uint32_t cbActual = 0;
476 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
477 if (rc != rcExp)
478 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",
479 rcExp, rc);
480 else if (pReqRet != pReq)
481 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",
482 pReq, pReqRet);
483 else if (RT_FAILURE(rcExp))
484 retval = true;
485 else
486 {
487 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
488 RTUTF16 *pwcExp = wcExp;
489 size_t cwc = 0;
490 rc = RTStrToUtf16Ex(pcszExp, RTSTR_MAX, &pwcExp,
491 RT_ELEMENTS(wcExp), &cwc);
492 size_t cbExp = cwc * 2 + 2;
493 AssertRC(rc);
494 if (RT_SUCCESS(rc))
495 {
496 if (cbActual != cbExp)
497 {
498 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",
499 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,
500 pcszExp, cbExp);
501 }
502 else
503 {
504 if (memcmp(pc, wcExp, cbExp) == 0)
505 retval = true;
506 else
507 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",
508 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);
509 }
510 }
511 }
512 }
513 if (!retval)
514 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",
515 pcszExp, rcExp);
516}
517
518static void tstLatin1FromX11(RTTEST hTest, PSHCLX11CTX pCtx,
519 const char *pcszExp, int rcExp)
520{
521 bool retval = false;
522 tstClipSendTargetUpdate(pCtx);
523 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
524 RTTestFailed(hTest, "Wrong targets reported: %02X\n",
525 tstClipQueryFormats());
526 else
527 {
528 char *pc;
529 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
530 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
531 int rc = VINF_SUCCESS;
532 uint32_t cbActual = 0;
533 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
534 if (rc != rcExp)
535 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",
536 rcExp, rc);
537 else if (pReqRet != pReq)
538 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",
539 pReq, pReqRet);
540 else if (RT_FAILURE(rcExp))
541 retval = true;
542 else
543 {
544 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
545 //RTUTF16 *pwcExp = wcExp; - unused
546 size_t cwc;
547 for (cwc = 0; cwc == 0 || pcszExp[cwc - 1] != '\0'; ++cwc)
548 wcExp[cwc] = pcszExp[cwc];
549 size_t cbExp = cwc * 2;
550 if (cbActual != cbExp)
551 {
552 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",
553 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,
554 pcszExp, cbExp);
555 }
556 else
557 {
558 if (memcmp(pc, wcExp, cbExp) == 0)
559 retval = true;
560 else
561 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",
562 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);
563 }
564 }
565 }
566 if (!retval)
567 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",
568 pcszExp, rcExp);
569}
570
571static void tstStringFromVBox(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget, Atom typeExp, const char *valueExp)
572{
573 RT_NOREF(pCtx);
574 bool retval = false;
575 Atom type;
576 XtPointer value = NULL;
577 unsigned long length;
578 int format;
579 size_t lenExp = strlen(valueExp);
580 if (tstClipConvertSelection(pcszTarget, &type, &value, &length, &format))
581 {
582 if ( type != typeExp
583 || length != lenExp
584 || format != 8
585 || memcmp((const void *) value, (const void *)valueExp,
586 lenExp))
587 {
588 RTTestFailed(hTest, "Bad data: type %d, (expected %d), length %u, (expected %u), format %d (expected %d), value \"%.*s\" (expected \"%.*s\")\n",
589 type, typeExp, length, lenExp, format, 8,
590 RT_MIN(length, 20), value, RT_MIN(lenExp, 20), valueExp);
591 }
592 else
593 retval = true;
594 }
595 else
596 RTTestFailed(hTest, "Conversion failed\n");
597 XtFree((char *)value);
598 if (!retval)
599 RTTestFailureDetails(hTest, "Conversion to %s, expected \"%s\"\n",
600 pcszTarget, valueExp);
601}
602
603static void tstNoX11(PSHCLX11CTX pCtx, const char *pcszTestCtx)
604{
605 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq;
606 int rc = ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
607 RTTESTI_CHECK_MSG(rc == VERR_NO_DATA, ("context: %s\n", pcszTestCtx));
608}
609
610static void tstStringFromVBoxFailed(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget)
611{
612 RT_NOREF(pCtx);
613 Atom type;
614 XtPointer value = NULL;
615 unsigned long length;
616 int format;
617 RTTEST_CHECK_MSG(hTest, !tstClipConvertSelection(pcszTarget, &type, &value,
618 &length, &format),
619 (hTest, "Conversion to target %s, should have failed but didn't, returned type %d, length %u, format %d, value \"%.*s\"\n",
620 pcszTarget, type, length, format, RT_MIN(length, 20),
621 value));
622 XtFree((char *)value);
623}
624
625static void tstNoSelectionOwnership(PSHCLX11CTX pCtx, const char *pcszTestCtx)
626{
627 RT_NOREF(pCtx);
628 RTTESTI_CHECK_MSG(!g_tst_fOwnsSel, ("context: %s\n", pcszTestCtx));
629}
630
631static void tstBadFormatRequestFromHost(RTTEST hTest, PSHCLX11CTX pCtx)
632{
633 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
634 sizeof("hello world"), 8);
635 tstClipSendTargetUpdate(pCtx);
636 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
637 RTTestFailed(hTest, "Wrong targets reported: %02X\n",
638 tstClipQueryFormats());
639 else
640 {
641 char *pc;
642 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
643 ShClX11ReadDataFromX11(pCtx, 0xF000 /* vboxFormat */, pReq); /* Bad format. */
644 int rc = VINF_SUCCESS;
645 uint32_t cbActual = 0;
646 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
647 if (rc != VERR_NOT_IMPLEMENTED)
648 RTTestFailed(hTest, "Wrong return code, expected VERR_NOT_IMPLEMENTED, got %Rrc\n",
649 rc);
650 tstClipSetSelectionValues("", XA_STRING, "", sizeof(""), 8);
651 tstClipSendTargetUpdate(pCtx);
652 if (tstClipQueryFormats() == VBOX_SHCL_FMT_UNICODETEXT)
653 RTTestFailed(hTest, "Failed to report targets after bad host request.\n");
654 }
655}
656
657int main()
658{
659 /*
660 * Init the runtime, test and say hello.
661 */
662 RTTEST hTest;
663 int rc = RTTestInitAndCreate("tstClipboardGH-X11", &hTest);
664 if (RT_FAILURE(rc))
665 return RTEXITCODE_FAILURE;
666 RTTestBanner(hTest);
667
668 /*
669 * Run the tests.
670 */
671 SHCLX11CTX X11Ctx;
672 rc = ShClX11Init(&X11Ctx, NULL /* pParent */, false /* fHeadless */);
673 AssertRCReturn(rc, RTEXITCODE_FAILURE);
674
675 char *pc;
676 uint32_t cbActual;
677 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
678
679 /* UTF-8 from X11 */
680 RTTestSub(hTest, "reading UTF-8 from X11");
681 /* Simple test */
682 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
683 sizeof("hello world"), 8);
684 tstStringFromX11(hTest, &X11Ctx, "hello world", VINF_SUCCESS);
685 /* With an embedded carriage return */
686 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,
687 "hello\nworld", sizeof("hello\nworld"), 8);
688 tstStringFromX11(hTest, &X11Ctx, "hello\r\nworld", VINF_SUCCESS);
689 /* With an embedded CRLF */
690 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,
691 "hello\r\nworld", sizeof("hello\r\nworld"), 8);
692 tstStringFromX11(hTest, &X11Ctx, "hello\r\r\nworld", VINF_SUCCESS);
693 /* With an embedded LFCR */
694 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,
695 "hello\n\rworld", sizeof("hello\n\rworld"), 8);
696 tstStringFromX11(hTest, &X11Ctx, "hello\r\n\rworld", VINF_SUCCESS);
697 /* An empty string */
698 tstClipSetSelectionValues("text/plain;charset=utf-8", XA_STRING, "",
699 sizeof(""), 8);
700 tstStringFromX11(hTest, &X11Ctx, "", VINF_SUCCESS);
701 /* With an embedded UTF-8 character. */
702 tstClipSetSelectionValues("STRING", XA_STRING,
703 "100\xE2\x82\xAC" /* 100 Euro */,
704 sizeof("100\xE2\x82\xAC"), 8);
705 tstStringFromX11(hTest, &X11Ctx, "100\xE2\x82\xAC", VINF_SUCCESS);
706 /* A non-zero-terminated string */
707 tstClipSetSelectionValues("TEXT", XA_STRING,
708 "hello world", sizeof("hello world") - 1, 8);
709 tstStringFromX11(hTest, &X11Ctx, "hello world", VINF_SUCCESS);
710
711 /* Latin1 from X11 */
712 RTTestSub(hTest, "reading Latin1 from X11");
713 /* Simple test */
714 tstClipSetSelectionValues("STRING", XA_STRING, "Georges Dupr\xEA",
715 sizeof("Georges Dupr\xEA"), 8);
716 tstLatin1FromX11(hTest, &X11Ctx, "Georges Dupr\xEA", VINF_SUCCESS);
717 /* With an embedded carriage return */
718 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\nDupr\xEA",
719 sizeof("Georges\nDupr\xEA"), 8);
720 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\nDupr\xEA", VINF_SUCCESS);
721 /* With an embedded CRLF */
722 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\r\nDupr\xEA",
723 sizeof("Georges\r\nDupr\xEA"), 8);
724 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\r\nDupr\xEA", VINF_SUCCESS);
725 /* With an embedded LFCR */
726 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\n\rDupr\xEA",
727 sizeof("Georges\n\rDupr\xEA"), 8);
728 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\n\rDupr\xEA", VINF_SUCCESS);
729 /* A non-zero-terminated string */
730 tstClipSetSelectionValues("text/plain", XA_STRING,
731 "Georges Dupr\xEA!",
732 sizeof("Georges Dupr\xEA!") - 1, 8);
733 tstLatin1FromX11(hTest, &X11Ctx, "Georges Dupr\xEA!", VINF_SUCCESS);
734
735 /*
736 * Unknown X11 format
737 */
738 RTTestSub(hTest, "handling of an unknown X11 format");
739 tstClipInvalidateFormats();
740 tstClipSetSelectionValues("CLIPBOARD", XA_STRING, "Test",
741 sizeof("Test"), 8);
742 tstClipSendTargetUpdate(&X11Ctx);
743 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,
744 (hTest, "Failed to send a format update notification\n"));
745
746 /*
747 * Timeout from X11
748 */
749 RTTestSub(hTest, "X11 timeout");
750 tstClipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, NULL,0, 8);
751 tstStringFromX11(hTest, &X11Ctx, "", VERR_NO_DATA);
752
753 /*
754 * No data in X11 clipboard
755 */
756 RTTestSub(hTest, "a data request from an empty X11 clipboard");
757 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, NULL,
758 0, 8);
759 ShClX11ReadDataFromX11(&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
760 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
761 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,
762 (hTest, "Returned %Rrc instead of VERR_NO_DATA\n",
763 rc));
764 RTTEST_CHECK_MSG(hTest, pReqRet == pReq,
765 (hTest, "Wrong returned request data, expected %p, got %p\n",
766 pReq, pReqRet));
767
768 /*
769 * Ensure that VBox is notified when we return the CB to X11
770 */
771 RTTestSub(hTest, "notification of switch to X11 clipboard");
772 tstClipInvalidateFormats();
773 clipReportEmpty(&X11Ctx);
774 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,
775 (hTest, "Failed to send a format update (release) notification\n"));
776
777 /*
778 * Request for an invalid VBox format from X11
779 */
780 RTTestSub(hTest, "a request for an invalid VBox format from X11");
781 /* Testing for 0xffff will go into handling VBOX_SHCL_FMT_UNICODETEXT, where we don't have
782 * have any data at the moment so far, so this will return VERR_NO_DATA. */
783 ShClX11ReadDataFromX11(&X11Ctx, 0xffff /* vboxFormat */, pReq);
784 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
785 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,
786 (hTest, "Returned %Rrc instead of VERR_NO_DATA\n",
787 rc));
788 RTTEST_CHECK_MSG(hTest, pReqRet == pReq,
789 (hTest, "Wrong returned request data, expected %p, got %p\n",
790 pReq, pReqRet));
791
792 /*
793 * Targets failure from X11
794 */
795 RTTestSub(hTest, "X11 targets conversion failure");
796 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
797 sizeof("hello world"), 8);
798 tstClipSetTargetsFailure();
799 Atom atom = XA_STRING;
800 long unsigned int cLen = 0;
801 int format = 8;
802 clipConvertX11TargetsCallback(NULL, (XtPointer) &X11Ctx, NULL, &atom, NULL, &cLen,
803 &format);
804 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,
805 (hTest, "Wrong targets reported: %02X\n",
806 tstClipQueryFormats()));
807
808 /*
809 * X11 text format conversion
810 */
811 RTTestSub(hTest, "handling of X11 selection targets");
812 RTTEST_CHECK_MSG(hTest, tstClipTextFormatConversion(&X11Ctx),
813 (hTest, "failed to select the right X11 text formats\n"));
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 ShClX11Destroy(&X11Ctx);
891
892 /*
893 * Headless clipboard tests
894 */
895 rc = ShClX11Init(&X11Ctx, NULL /* pParent */, true /* fHeadless */);
896 AssertRCReturn(rc, RTEXITCODE_FAILURE);
897
898 /* Read from X11 */
899 RTTestSub(hTest, "reading from X11, headless clipboard");
900 /* Simple test */
901 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "",
902 sizeof("") * 2);
903 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
904 sizeof("hello world"), 8);
905 tstNoX11(&X11Ctx, "reading from X11, headless clipboard");
906
907 /* Read from VBox */
908 RTTestSub(hTest, "reading from VBox, headless clipboard");
909 /* Simple test */
910 tstClipEmptyVBox(&X11Ctx, VERR_WRONG_ORDER);
911 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
912 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
913 sizeof("hello world") * 2);
914 tstNoSelectionOwnership(&X11Ctx, "reading from VBox, headless clipboard");
915
916 ShClX11Destroy(&X11Ctx);
917
918 return RTTestSummaryAndDestroy(hTest);
919}
920
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