VirtualBox

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

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

Shared Clipboard/Transfers: More code for HTTP transfers. bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.6 KB
Line 
1/* $Id: tstClipboardGH-X11.cpp 87452 2021-01-27 17:11: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 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
121/** @copydoc ShClX11RequestDataForX11Callback */
122DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, uint32_t uFmt, void **ppv, uint32_t *pcb)
123{
124 RT_NOREF(pCtx, uFmt);
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 size_t const cFormats = clipReportMaxX11Formats();
190 size_t i;
191 for (i = 0; i < cFormats; ++i)
192 {
193 if (!strcmp(pcsz, g_aFormats[i].pcszAtom))
194 atom = (Atom) (i + 0x1000);
195 }
196 for (i = 0; i < RT_ELEMENTS(g_tst_apszSupAtoms); ++i)
197 if (!strcmp(pcsz, g_tst_apszSupAtoms[i]))
198 atom = (Atom) (i + 0x2000);
199 Assert(atom); /* Have we missed any atoms? */
200 return atom;
201}
202
203/* Take a request for the targets we are currently offering. */
204static SHCLX11FMTIDX g_tst_aSelTargetsIdx[10] = { 0 };
205static size_t g_tst_cTargets = 0;
206
207void tstRequestTargets(SHCLX11CTX* pCtx)
208{
209 clipUpdateX11Targets(pCtx, g_tst_aSelTargetsIdx, g_tst_cTargets);
210}
211
212/* The current values of the X selection, which will be returned to the
213 * XtGetSelectionValue callback. */
214static Atom g_tst_atmSelType = 0;
215static const void *g_tst_pSelData = NULL;
216static unsigned long g_tst_cSelData = 0;
217static int g_tst_selFormat = 0;
218
219void tstClipRequestData(PSHCLX11CTX pCtx, SHCLX11FMTIDX target, void *closure)
220{
221 RT_NOREF(pCtx);
222 unsigned long count = 0;
223 int format = 0;
224 if (target != g_tst_aSelTargetsIdx[0])
225 {
226 clipConvertDataFromX11Worker(closure, NULL, 0); /* Could not convert to target. */
227 return;
228 }
229 void *pValue = NULL;
230 pValue = g_tst_pSelData ? RTMemDup(g_tst_pSelData, g_tst_cSelData) : NULL;
231 count = g_tst_pSelData ? g_tst_cSelData : 0;
232 format = g_tst_selFormat;
233 if (!pValue)
234 {
235 count = 0;
236 format = 0;
237 }
238 clipConvertDataFromX11Worker(closure, pValue, count * format / 8);
239 if (pValue)
240 RTMemFree(pValue);
241}
242
243/* The formats currently on offer from X11 via the shared clipboard. */
244static uint32_t g_tst_uX11Formats = 0;
245
246/** @copydoc ShClX11ReportFormatsCallback */
247DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, SHCLFORMATS fFormats)
248{
249 RT_NOREF(pCtx);
250 g_tst_uX11Formats = fFormats;
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 clipQueryX11Formats(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
402/** @copydoc ShClX11RequestFromX11CompleteCallback */
403void ShClX11RequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
404{
405 RT_NOREF(pCtx);
406 if (cb <= TESTCASE_MAX_BUF_SIZE)
407 {
408 g_tst_rcCompleted = rc;
409 if (cb != 0)
410 memcpy(g_tst_abCompletedBuf, pv, cb);
411 }
412 else
413 g_tst_rcCompleted = VERR_BUFFER_OVERFLOW;
414 g_tst_cbCompleted = cb;
415 g_tst_pCompletedReq = pReq;
416}
417
418/**
419 * Looks up the X11 format matching a given X11 atom text.
420 *
421 * @returns the format on success, NIL_CLIPX11FORMAT on failure
422 * @param pcszAtom Atom text to look up format for.
423 */
424static SHCLX11FMTIDX tstClipFindX11FormatByAtomText(const char *pcszAtom)
425{
426 const size_t j = clipReportMaxX11Formats();
427
428 for (unsigned i = 0; i < j; ++i)
429 {
430 if (!strcmp(g_aFormats[i].pcszAtom, pcszAtom))
431 return i;
432 }
433 return NIL_CLIPX11FORMAT;
434}
435
436static bool tstClipTextFormatConversion(PSHCLX11CTX pCtx)
437{
438 bool fSuccess = true;
439 SHCLX11FMTIDX targets[2];
440 SHCLX11FMTIDX x11Format;
441 targets[0] = tstClipFindX11FormatByAtomText("text/plain");
442 targets[1] = tstClipFindX11FormatByAtomText("image/bmp");
443 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
444 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_TEXT)
445 fSuccess = false;
446 targets[0] = tstClipFindX11FormatByAtomText("UTF8_STRING");
447 targets[1] = tstClipFindX11FormatByAtomText("text/plain");
448 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
449 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_UTF8)
450 fSuccess = false;
451 return fSuccess;
452}
453
454static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, CLIPREADCBREQ **ppReq)
455{
456 *prc = g_tst_rcCompleted;
457 *ppc = g_tst_abCompletedBuf;
458 *pcb = g_tst_cbCompleted;
459 *ppReq = g_tst_pCompletedReq;
460}
461
462static void tstStringFromX11(RTTEST hTest, PSHCLX11CTX pCtx,
463 const char *pcszExp, int rcExp)
464{
465 bool retval = true;
466 tstClipSendTargetUpdate(pCtx);
467 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
468 {
469 RTTestFailed(hTest, "Wrong targets reported: %02X\n", tstClipQueryFormats());
470 }
471 else
472 {
473 char *pc;
474 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
475 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
476 int rc = VINF_SUCCESS;
477 uint32_t cbActual = 0;
478 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
479 if (rc != rcExp)
480 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",
481 rcExp, rc);
482 else if (pReqRet != pReq)
483 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",
484 pReq, pReqRet);
485 else if (RT_FAILURE(rcExp))
486 retval = true;
487 else
488 {
489 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
490 RTUTF16 *pwcExp = wcExp;
491 size_t cwc = 0;
492 rc = RTStrToUtf16Ex(pcszExp, RTSTR_MAX, &pwcExp,
493 RT_ELEMENTS(wcExp), &cwc);
494 size_t cbExp = cwc * 2 + 2;
495 AssertRC(rc);
496 if (RT_SUCCESS(rc))
497 {
498 if (cbActual != cbExp)
499 {
500 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",
501 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,
502 pcszExp, cbExp);
503 }
504 else
505 {
506 if (memcmp(pc, wcExp, cbExp) == 0)
507 retval = true;
508 else
509 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",
510 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);
511 }
512 }
513 }
514 }
515 if (!retval)
516 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",
517 pcszExp, rcExp);
518}
519
520static void tstLatin1FromX11(RTTEST hTest, PSHCLX11CTX pCtx,
521 const char *pcszExp, int rcExp)
522{
523 bool retval = false;
524 tstClipSendTargetUpdate(pCtx);
525 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
526 RTTestFailed(hTest, "Wrong targets reported: %02X\n",
527 tstClipQueryFormats());
528 else
529 {
530 char *pc;
531 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
532 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
533 int rc = VINF_SUCCESS;
534 uint32_t cbActual = 0;
535 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
536 if (rc != rcExp)
537 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",
538 rcExp, rc);
539 else if (pReqRet != pReq)
540 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",
541 pReq, pReqRet);
542 else if (RT_FAILURE(rcExp))
543 retval = true;
544 else
545 {
546 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
547 //RTUTF16 *pwcExp = wcExp; - unused
548 size_t cwc;
549 for (cwc = 0; cwc == 0 || pcszExp[cwc - 1] != '\0'; ++cwc)
550 wcExp[cwc] = pcszExp[cwc];
551 size_t cbExp = cwc * 2;
552 if (cbActual != cbExp)
553 {
554 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",
555 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,
556 pcszExp, cbExp);
557 }
558 else
559 {
560 if (memcmp(pc, wcExp, cbExp) == 0)
561 retval = true;
562 else
563 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",
564 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);
565 }
566 }
567 }
568 if (!retval)
569 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",
570 pcszExp, rcExp);
571}
572
573static void tstStringFromVBox(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget, Atom typeExp, const char *valueExp)
574{
575 RT_NOREF(pCtx);
576 bool retval = false;
577 Atom type;
578 XtPointer value = NULL;
579 unsigned long length;
580 int format;
581 size_t lenExp = strlen(valueExp);
582 if (tstClipConvertSelection(pcszTarget, &type, &value, &length, &format))
583 {
584 if ( type != typeExp
585 || length != lenExp
586 || format != 8
587 || memcmp((const void *) value, (const void *)valueExp,
588 lenExp))
589 {
590 RTTestFailed(hTest, "Bad data: type %d, (expected %d), length %u, (expected %u), format %d (expected %d), value \"%.*s\" (expected \"%.*s\")\n",
591 type, typeExp, length, lenExp, format, 8,
592 RT_MIN(length, 20), value, RT_MIN(lenExp, 20), valueExp);
593 }
594 else
595 retval = true;
596 }
597 else
598 RTTestFailed(hTest, "Conversion failed\n");
599 XtFree((char *)value);
600 if (!retval)
601 RTTestFailureDetails(hTest, "Conversion to %s, expected \"%s\"\n",
602 pcszTarget, valueExp);
603}
604
605static void tstNoX11(PSHCLX11CTX pCtx, const char *pcszTestCtx)
606{
607 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq;
608 int rc = ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
609 RTTESTI_CHECK_MSG(rc == VERR_NO_DATA, ("context: %s\n", pcszTestCtx));
610}
611
612static void tstStringFromVBoxFailed(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget)
613{
614 RT_NOREF(pCtx);
615 Atom type;
616 XtPointer value = NULL;
617 unsigned long length;
618 int format;
619 RTTEST_CHECK_MSG(hTest, !tstClipConvertSelection(pcszTarget, &type, &value,
620 &length, &format),
621 (hTest, "Conversion to target %s, should have failed but didn't, returned type %d, length %u, format %d, value \"%.*s\"\n",
622 pcszTarget, type, length, format, RT_MIN(length, 20),
623 value));
624 XtFree((char *)value);
625}
626
627static void tstNoSelectionOwnership(PSHCLX11CTX pCtx, const char *pcszTestCtx)
628{
629 RT_NOREF(pCtx);
630 RTTESTI_CHECK_MSG(!g_tst_fOwnsSel, ("context: %s\n", pcszTestCtx));
631}
632
633static void tstBadFormatRequestFromHost(RTTEST hTest, PSHCLX11CTX pCtx)
634{
635 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
636 sizeof("hello world"), 8);
637 tstClipSendTargetUpdate(pCtx);
638 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)
639 RTTestFailed(hTest, "Wrong targets reported: %02X\n",
640 tstClipQueryFormats());
641 else
642 {
643 char *pc;
644 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
645 ShClX11ReadDataFromX11(pCtx, 0xF000 /* vboxFormat */, pReq); /* Bad format. */
646 int rc = VINF_SUCCESS;
647 uint32_t cbActual = 0;
648 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
649 if (rc != VERR_NOT_IMPLEMENTED)
650 RTTestFailed(hTest, "Wrong return code, expected VERR_NOT_IMPLEMENTED, got %Rrc\n",
651 rc);
652 tstClipSetSelectionValues("", XA_STRING, "", sizeof(""), 8);
653 tstClipSendTargetUpdate(pCtx);
654 if (tstClipQueryFormats() == VBOX_SHCL_FMT_UNICODETEXT)
655 RTTestFailed(hTest, "Failed to report targets after bad host request.\n");
656 }
657}
658
659int main()
660{
661 /*
662 * Init the runtime, test and say hello.
663 */
664 RTTEST hTest;
665 int rc = RTTestInitAndCreate("tstClipboardGH-X11", &hTest);
666 if (RT_FAILURE(rc))
667 return RTEXITCODE_FAILURE;
668 RTTestBanner(hTest);
669
670 /*
671 * Run the tests.
672 */
673 SHCLX11CTX X11Ctx;
674 rc = ShClX11Init(&X11Ctx, NULL /* pParent */, false /* fHeadless */);
675 AssertRCReturn(rc, RTEXITCODE_FAILURE);
676
677 char *pc;
678 uint32_t cbActual;
679 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
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 clipReportEmpty(&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 * UTF-8 from VBox
818 */
819 RTTestSub(hTest, "reading UTF-8 from VBox");
820 /* Simple test */
821 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
822 sizeof("hello world") * 2);
823 tstStringFromVBox(hTest, &X11Ctx, "UTF8_STRING",
824 clipGetAtom(&X11Ctx, "UTF8_STRING"), "hello world");
825 /* With an embedded carriage return */
826 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\nworld",
827 sizeof("hello\r\nworld") * 2);
828 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",
829 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),
830 "hello\nworld");
831 /* With an embedded CRCRLF */
832 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\r\nworld",
833 sizeof("hello\r\r\nworld") * 2);
834 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",
835 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),
836 "hello\r\nworld");
837 /* With an embedded CRLFCR */
838 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\n\rworld",
839 sizeof("hello\r\n\rworld") * 2);
840 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",
841 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),
842 "hello\n\rworld");
843 /* An empty string */
844 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);
845 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=utf-8",
846 clipGetAtom(&X11Ctx, "text/plain;charset=utf-8"), "");
847 /* With an embedded UTF-8 character. */
848 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */,
849 10);
850 tstStringFromVBox(hTest, &X11Ctx, "STRING",
851 clipGetAtom(&X11Ctx, "STRING"), "100\xE2\x82\xAC");
852 /* A non-zero-terminated string */
853 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
854 sizeof("hello world") * 2 - 2);
855 tstStringFromVBox(hTest, &X11Ctx, "TEXT", clipGetAtom(&X11Ctx, "TEXT"),
856 "hello world");
857
858 /*
859 * Timeout from VBox
860 */
861 RTTestSub(hTest, "reading from VBox with timeout");
862 tstClipEmptyVBox(&X11Ctx, VERR_TIMEOUT);
863 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");
864
865 /*
866 * No data in VBox clipboard
867 */
868 RTTestSub(hTest, "an empty VBox clipboard");
869 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
870 tstClipEmptyVBox(&X11Ctx, VINF_SUCCESS);
871 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,
872 (hTest, "VBox grabbed the clipboard with no data and we ignored it\n"));
873 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");
874
875 /*
876 * An unknown VBox format
877 */
878 RTTestSub(hTest, "reading an unknown VBox format");
879 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
880 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);
881 ShClX11ReportFormatsToX11(&X11Ctx, 0xa0000);
882 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,
883 (hTest, "VBox grabbed the clipboard with unknown data and we ignored it\n"));
884 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");
885
886 /*
887 * VBox requests a bad format
888 */
889 RTTestSub(hTest, "recovery from a bad format request");
890 tstBadFormatRequestFromHost(hTest, &X11Ctx);
891
892 ShClX11Destroy(&X11Ctx);
893
894 /*
895 * Headless clipboard tests
896 */
897 rc = ShClX11Init(&X11Ctx, NULL /* pParent */, true /* fHeadless */);
898 AssertRCReturn(rc, RTEXITCODE_FAILURE);
899
900 /* Read from X11 */
901 RTTestSub(hTest, "reading from X11, headless clipboard");
902 /* Simple test */
903 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "",
904 sizeof("") * 2);
905 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
906 sizeof("hello world"), 8);
907 tstNoX11(&X11Ctx, "reading from X11, headless clipboard");
908
909 /* Read from VBox */
910 RTTestSub(hTest, "reading from VBox, headless clipboard");
911 /* Simple test */
912 tstClipEmptyVBox(&X11Ctx, VERR_WRONG_ORDER);
913 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
914 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",
915 sizeof("hello world") * 2);
916 tstNoSelectionOwnership(&X11Ctx, "reading from VBox, headless clipboard");
917
918 ShClX11Destroy(&X11Ctx);
919
920 return RTTestSummaryAndDestroy(hTest);
921}
922
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