VirtualBox

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

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

GA/Linux: bugref:9804: Trunk GAs have a VBoxClient shared clipboard assertion crash problem on Linux 3.10 kernels

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