VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardMockHGCM.cpp@ 105745

Last change on this file since 105745 was 103631, checked in by vboxsync, 9 months ago

Shared Clipboard: More cleanups (renaming Windows parts to match the other platforms). bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: tstClipboardMockHGCM.cpp 103631 2024-03-01 11:00:38Z vboxsync $ */
2/** @file
3 * Shared Clipboard host service test case.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "../VBoxSharedClipboardSvc-internal.h"
33
34#include <VBox/HostServices/VBoxClipboardSvc.h>
35#include <VBox/VBoxGuestLib.h>
36#ifdef RT_OS_LINUX
37# include <VBox/GuestHost/SharedClipboard-x11.h>
38#endif
39#ifdef RT_OS_WINDOWS
40# include <VBox/GuestHost/SharedClipboard-win.h>
41#endif
42
43#include <VBox/HostServices/TstHGCMMock.h>
44#include <VBox/HostServices/TstHGCMMockUtils.h>
45
46#include <iprt/assert.h>
47#include <iprt/initterm.h>
48#include <iprt/mem.h>
49#include <iprt/rand.h>
50#include <iprt/stream.h>
51#include <iprt/string.h>
52#include <iprt/test.h>
53#include <iprt/utf16.h>
54
55
56/*********************************************************************************************************************************
57* Global Variables *
58*********************************************************************************************************************************/
59static RTTEST g_hTest;
60
61
62/*********************************************************************************************************************************
63* Shared Clipboard testing *
64*********************************************************************************************************************************/
65struct CLIPBOARDTESTDESC;
66/** Pointer to a test description. */
67typedef CLIPBOARDTESTDESC *PTESTDESC;
68
69struct CLIPBOARDTESTCTX;
70/** Pointer to a test context. */
71typedef CLIPBOARDTESTCTX *PCLIPBOARDTESTCTX;
72
73/** Pointer a test descriptor. */
74typedef CLIPBOARDTESTDESC *PTESTDESC;
75
76typedef DECLCALLBACKTYPE(int, FNTESTSETUP,(PCLIPBOARDTESTCTX pTstCtx, void **ppvCtx));
77/** Pointer to a test setup callback. */
78typedef FNTESTSETUP *PFNTESTSETUP;
79
80typedef DECLCALLBACKTYPE(int, FNTESTEXEC,(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx));
81/** Pointer to a test exec callback. */
82typedef FNTESTEXEC *PFNTESTEXEC;
83
84typedef DECLCALLBACKTYPE(int, FNTESTDESTROY,(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx));
85/** Pointer to a test destroy callback. */
86typedef FNTESTDESTROY *PFNTESTDESTROY;
87
88
89/**
90 * Structure for keeping a clipboard test task.
91 */
92typedef struct CLIPBOARDTESTTASK
93{
94 SHCLFORMATS enmFmtHst;
95 SHCLFORMATS enmFmtGst;
96 /** For testing chunked reads / writes. */
97 size_t cbChunk;
98 /** Data buffer to read / write for this task.
99 * Can be NULL if not needed. */
100 void *pvData;
101 /** Size (in bytes) of \a pvData. */
102 size_t cbData;
103 /** Number of bytes read / written from / to \a pvData. */
104 size_t cbProcessed;
105} CLIPBOARDTESTTASK;
106typedef CLIPBOARDTESTTASK *PCLIPBOARDTESTTASK;
107
108/**
109 * Structure for keeping a clipboard test context.
110 */
111typedef struct CLIPBOARDTESTCTX
112{
113 /** The HGCM Mock utils context. */
114 TSTHGCMUTILSCTX HGCM;
115 /** Clipboard-specific task data. */
116 CLIPBOARDTESTTASK Task;
117 struct
118 {
119 /** The VbglR3 Shared Clipboard context to work on. */
120 VBGLR3SHCLCMDCTX CmdCtx;
121 } Guest;
122} CLIPBOARDTESTCTX;
123
124/** The one and only clipboard test context. One at a time. */
125CLIPBOARDTESTCTX g_TstCtx;
126
127/**
128 * Structure for keeping a clipboard test description.
129 */
130typedef struct CLIPBOARDTESTDESC
131{
132 /** The setup callback. */
133 PFNTESTSETUP pfnSetup;
134 /** The exec callback. */
135 PFNTESTEXEC pfnExec;
136 /** The destruction callback. */
137 PFNTESTDESTROY pfnDestroy;
138} CLIPBOARDTESTDESC;
139
140typedef struct SHCLCONTEXT
141{
142} SHCLCONTEXT;
143
144
145static int tstSetModeRc(PTSTHGCMMOCKSVC pSvc, uint32_t uMode, int rcExpected)
146{
147 VBOXHGCMSVCPARM aParms[2];
148 HGCMSvcSetU32(&aParms[0], uMode);
149 int rc2 = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, aParms);
150 RTTESTI_CHECK_MSG_RET(rcExpected == rc2, ("Expected %Rrc, got %Rrc\n", rcExpected, rc2), rc2);
151 if (RT_SUCCESS(rcExpected))
152 {
153 uint32_t const uModeRet = ShClSvcGetMode();
154 RTTESTI_CHECK_MSG_RET(uMode == uModeRet, ("Expected mode %RU32, got %RU32\n", uMode, uModeRet), VERR_WRONG_TYPE);
155 }
156 return rc2;
157}
158
159static int tstClipboardSetMode(PTSTHGCMMOCKSVC pSvc, uint32_t uMode)
160{
161 return tstSetModeRc(pSvc, uMode, VINF_SUCCESS);
162}
163
164static bool tstClipboardGetMode(PTSTHGCMMOCKSVC pSvc, uint32_t uModeExpected)
165{
166 RT_NOREF(pSvc);
167 RTTESTI_CHECK_RET(ShClSvcGetMode() == uModeExpected, false);
168 return true;
169}
170
171static void tstOperationModes(void)
172{
173 struct VBOXHGCMSVCPARM parms[2];
174 uint32_t u32Mode;
175 int rc;
176
177 RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_MODE");
178
179 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
180
181 /* Reset global variable which doesn't reset itself. */
182 HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_OFF);
183 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
184 RTTESTI_CHECK_RC_OK(rc);
185 u32Mode = ShClSvcGetMode();
186 RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_OFF, ("u32Mode=%u\n", (unsigned) u32Mode));
187
188 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 0, parms);
189 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
190
191 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 2, parms);
192 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
193
194 HGCMSvcSetU64(&parms[0], 99);
195 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
196 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
197
198 tstClipboardSetMode(pSvc, VBOX_SHCL_MODE_HOST_TO_GUEST);
199 tstSetModeRc(pSvc, 99, VERR_NOT_SUPPORTED);
200 tstClipboardGetMode(pSvc, VBOX_SHCL_MODE_OFF);
201}
202
203#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
204static void testSetTransferMode(void)
205{
206 RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE");
207
208 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
209
210 /* Invalid parameter. */
211 VBOXHGCMSVCPARM parms[2];
212 HGCMSvcSetU64(&parms[0], 99);
213 int rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
214 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
215
216 /* Invalid mode. */
217 HGCMSvcSetU32(&parms[0], 99);
218 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
219 RTTESTI_CHECK_RC(rc, VERR_INVALID_FLAGS);
220
221 /* Enable transfers. */
222 HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_F_ENABLED);
223 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
224 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
225
226 /* Disable transfers again. */
227 HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_F_NONE);
228 rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
229 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
230}
231#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
232
233static void testGuestSimple(void)
234{
235 RTTestISub("Testing client (guest) API - Simple");
236
237 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
238
239 /* Preparations. */
240 VBGLR3SHCLCMDCTX Ctx;
241 RT_ZERO(Ctx);
242
243 /*
244 * Multiple connects / disconnects.
245 */
246 RTTESTI_CHECK_RC_OK(VbglR3ClipboardConnectEx(&Ctx, VBOX_SHCL_GF_0_CONTEXT_ID));
247 RTTESTI_CHECK_RC_OK(VbglR3ClipboardDisconnectEx(&Ctx));
248 /* Report bogus guest features while connecting. */
249 RTTESTI_CHECK_RC_OK(VbglR3ClipboardConnectEx(&Ctx, 0xdeadbeef));
250 RTTESTI_CHECK_RC_OK(VbglR3ClipboardDisconnectEx(&Ctx));
251
252 RTTESTI_CHECK_RC_OK(VbglR3ClipboardConnectEx(&Ctx, VBOX_SHCL_GF_0_CONTEXT_ID));
253
254 /*
255 * Feature tests.
256 */
257
258 RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFeatures(Ctx.idClient, 0x0, NULL /* pfHostFeatures */));
259 /* Report bogus features to the host. */
260 RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFeatures(Ctx.idClient, 0xdeadb33f, NULL /* pfHostFeatures */));
261
262 /*
263 * Access denied tests.
264 */
265
266 /* Try reading data from host. */
267 uint8_t abData[32]; uint32_t cbIgnored;
268 RTTESTI_CHECK_RC(VbglR3ClipboardReadData(Ctx.idClient, VBOX_SHCL_FMT_UNICODETEXT,
269 abData, sizeof(abData), &cbIgnored), VERR_ACCESS_DENIED);
270 /* Try writing data without reporting formats before (legacy). */
271 RTTESTI_CHECK_RC(VbglR3ClipboardWriteData(Ctx.idClient, 0xdeadb33f, abData, sizeof(abData)), VERR_ACCESS_DENIED);
272 /* Try writing data without reporting formats before. */
273 RTTESTI_CHECK_RC(VbglR3ClipboardWriteDataEx(&Ctx, 0xdeadb33f, abData, sizeof(abData)), VERR_ACCESS_DENIED);
274 /* Report bogus formats to the host. */
275 RTTESTI_CHECK_RC(VbglR3ClipboardReportFormats(Ctx.idClient, 0xdeadb33f), VERR_ACCESS_DENIED);
276 /* Report supported formats to host. */
277 RTTESTI_CHECK_RC(VbglR3ClipboardReportFormats(Ctx.idClient,
278 VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_BITMAP | VBOX_SHCL_FMT_HTML),
279 VERR_ACCESS_DENIED);
280 /*
281 * Access allowed tests.
282 */
283 tstClipboardSetMode(pSvc, VBOX_SHCL_MODE_BIDIRECTIONAL);
284
285 /* Try writing data without reporting formats before. */
286 RTTESTI_CHECK_RC_OK(VbglR3ClipboardWriteDataEx(&Ctx, 0xdeadb33f, abData, sizeof(abData)));
287 /* Try reading data from host. */
288 RTTESTI_CHECK_RC_OK(VbglR3ClipboardReadData(Ctx.idClient, VBOX_SHCL_FMT_UNICODETEXT,
289 abData, sizeof(abData), &cbIgnored));
290 /* Report bogus formats to the host. */
291 RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFormats(Ctx.idClient, 0xdeadb33f));
292 /* Report supported formats to host. */
293 RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFormats(Ctx.idClient,
294 VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_BITMAP | VBOX_SHCL_FMT_HTML));
295 /* Tear down. */
296 RTTESTI_CHECK_RC_OK(VbglR3ClipboardDisconnectEx(&Ctx));
297}
298
299static RTUTF16 tstGetRandUtf8(void)
300{
301 return RTRandU32Ex(0x20, 0x7A);
302}
303
304static char *tstGenerateUtf8StringA(uint32_t uCch)
305{
306 char * pszRand = (char *)RTMemAlloc(uCch + 1);
307 for (uint32_t i = 0; i < uCch; i++)
308 pszRand[i] = tstGetRandUtf8();
309 pszRand[uCch] = 0;
310 return pszRand;
311}
312
313#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
314static RTUTF16 tstGetRandUtf16(void)
315{
316 RTUTF16 wc;
317 do
318 {
319 wc = (RTUTF16)RTRandU32Ex(1, 0xfffd);
320 } while (wc >= 0xd800 && wc <= 0xdfff);
321 return wc;
322}
323
324static PRTUTF16 tstGenerateUtf16StringA(uint32_t uCch)
325{
326 PRTUTF16 pwszRand = (PRTUTF16)RTMemAlloc((uCch + 1) * sizeof(RTUTF16));
327 for (uint32_t i = 0; i < uCch; i++)
328 pwszRand[i] = tstGetRandUtf16();
329 pwszRand[uCch] = 0;
330 return pwszRand;
331}
332#endif /* RT_OS_WINDOWS) || RT_OS_OS2 */
333
334static void testSetHeadless(void)
335{
336 RTTestISub("Testing HOST_FN_SET_HEADLESS");
337
338 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
339
340 VBOXHGCMSVCPARM parms[2];
341 HGCMSvcSetU32(&parms[0], false);
342 int rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms);
343 RTTESTI_CHECK_RC_OK(rc);
344 bool fHeadless = ShClSvcGetHeadless();
345 RTTESTI_CHECK_MSG(fHeadless == false, ("fHeadless=%RTbool\n", fHeadless));
346 rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 0, parms);
347 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
348 rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 2, parms);
349 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
350 HGCMSvcSetU64(&parms[0], 99);
351 rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms);
352 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
353 HGCMSvcSetU32(&parms[0], true);
354 rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms);
355 RTTESTI_CHECK_RC_OK(rc);
356 fHeadless = ShClSvcGetHeadless();
357 RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless));
358 HGCMSvcSetU32(&parms[0], 99);
359 rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms);
360 RTTESTI_CHECK_RC_OK(rc);
361 fHeadless = ShClSvcGetHeadless();
362 RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless));
363}
364
365static void testHostCall(void)
366{
367 tstOperationModes();
368#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
369 testSetTransferMode();
370#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
371 testSetHeadless();
372}
373
374
375/*********************************************************************************************************************************
376 * Test: Guest reading from host *
377 ********************************************************************************************************************************/
378#if defined (RT_OS_LINUX) || defined (RT_OS_SOLARIS)
379/* Called from SHCLX11 thread. */
380static DECLCALLBACK(int) tstTestReadFromHost_ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
381{
382 RT_NOREF(pCtx, fFormats, pvUser);
383
384 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "tstTestReadFromHost_SvcReportFormatsCallback: fFormats=%#x\n", fFormats);
385 return VINF_SUCCESS;
386}
387
388/* Called by the backend, e.g. for X11 in the SHCLX11 thread. */
389static DECLCALLBACK(int) tstTestReadFromHost_OnClipboardReadCallback(PSHCLCONTEXT pCtx,
390 SHCLFORMAT uFmt, void **ppv, size_t *pcb, void *pvUser)
391{
392 RT_NOREF(pCtx, uFmt, pvUser);
393
394 PCLIPBOARDTESTTASK pTask = (PCLIPBOARDTESTTASK)TstHGCMUtilsTaskGetCurrent(&g_TstCtx.HGCM)->pvUser;
395
396 void *pvData = NULL;
397 size_t cbData = pTask->cbData - pTask->cbProcessed;
398 if (cbData)
399 {
400 pvData = RTMemDup((uint8_t *)pTask->pvData + pTask->cbProcessed, cbData);
401 AssertPtr(pvData);
402 }
403
404 RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Host reporting back %RU32 bytes of data\n", cbData);
405
406 *ppv = pvData;
407 *pcb = cbData;
408
409 return VINF_SUCCESS;
410}
411#endif /* (RT_OS_LINUX) || defined (RT_OS_SOLARIS) */
412
413typedef struct TSTUSERMOCK
414{
415#if defined(RT_OS_LINUX)
416 SHCLX11CTX X11Ctx;
417#endif
418 PSHCLCONTEXT pCtx;
419} TSTUSERMOCK;
420typedef TSTUSERMOCK *PTSTUSERMOCK;
421
422static void tstTestReadFromHost_MockInit(PTSTUSERMOCK pUsrMock, const char *pszName)
423{
424#if defined(RT_OS_LINUX)
425 SHCLCALLBACKS Callbacks;
426 RT_ZERO(Callbacks);
427 Callbacks.pfnReportFormats = tstTestReadFromHost_ReportFormatsCallback;
428 Callbacks.pfnOnClipboardRead = tstTestReadFromHost_OnClipboardReadCallback;
429
430 pUsrMock->pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
431 AssertPtrReturnVoid(pUsrMock->pCtx);
432
433 ShClX11Init(&pUsrMock->X11Ctx, &Callbacks, pUsrMock->pCtx, false);
434 ShClX11ThreadStartEx(&pUsrMock->X11Ctx, pszName, false /* fGrab */);
435 /* Give the clipboard time to synchronise. */
436 RTThreadSleep(500);
437#else
438 RT_NOREF(pUsrMock, pszName);
439#endif /* RT_OS_LINUX */
440}
441
442static void tstTestReadFromHost_MockDestroy(PTSTUSERMOCK pUsrMock)
443{
444#if defined(RT_OS_LINUX)
445 ShClX11ThreadStop(&pUsrMock->X11Ctx);
446 ShClX11Destroy(&pUsrMock->X11Ctx);
447 RTMemFree(pUsrMock->pCtx);
448#else
449 RT_NOREF(pUsrMock);
450#endif
451}
452
453static int tstTestReadFromHost_DoIt(PCLIPBOARDTESTCTX pCtx, PCLIPBOARDTESTTASK pTask)
454{
455 size_t cbDst = RT_MAX(_64K, pTask->cbData);
456 uint8_t *pabDst = (uint8_t *)RTMemAllocZ(cbDst);
457 AssertPtrReturn(pabDst, VERR_NO_MEMORY);
458
459 AssertPtr(pTask->pvData); /* Racing condition with host thread? */
460 Assert(pTask->cbChunk); /* Buggy test? */
461 Assert(pTask->cbChunk <= pTask->cbData); /* Ditto. */
462
463 size_t cbToRead = pTask->cbData;
464 switch (pTask->enmFmtGst)
465 {
466 case VBOX_SHCL_FMT_UNICODETEXT:
467#ifndef RT_OS_WINDOWS /** @todo Not sure about OS/2. */
468 cbToRead *= sizeof(RTUTF16);
469#endif
470 break;
471
472 default:
473 break;
474 }
475
476 PVBGLR3SHCLCMDCTX pCmdCtx = &pCtx->Guest.CmdCtx;
477
478 /* Do random chunked reads. */
479 uint32_t const cChunkedReads = RTRandU32Ex(1, 16);
480 RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "%RU32 chunked reads\n", cChunkedReads);
481 for (uint32_t i = 0; i < cChunkedReads; i++)
482 {
483 /* Note! VbglR3ClipboardReadData() currently does not support chunked reads!
484 * It in turn returns VINF_BUFFER_OVERFLOW when the supplied buffer was too small. */
485
486 uint32_t cbChunk = RTRandU32Ex(1, (uint32_t)(pTask->cbData / cChunkedReads));
487 uint32_t cbRead = 0;
488 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Guest trying to read %RU32 bytes\n", cbChunk);
489 int vrc2 = VbglR3ClipboardReadData(pCmdCtx->idClient, pTask->enmFmtGst, pabDst, cbChunk, &cbRead);
490 if ( vrc2 == VINF_SUCCESS
491 && cbRead == 0) /* No data there yet? */
492 {
493 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "No data (yet) from host\n");
494 RTThreadSleep(10);
495 continue;
496 }
497 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Trying reading host clipboard data with a %RU32 buffer -> %Rrc (%RU32)\n", cbChunk, vrc2, cbRead);
498 RTTEST_CHECK_MSG(g_hTest, vrc2 == VINF_BUFFER_OVERFLOW, (g_hTest, "Got %Rrc, expected VINF_BUFFER_OVERFLOW\n", vrc2));
499 }
500
501 /* Last read: Read the data with a buffer big enough. This must succeed. */
502 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Reading full data (%zu)\n", pTask->cbData);
503 uint32_t cbRead = 0;
504 int vrc2 = VbglR3ClipboardReadData(pCmdCtx->idClient, pTask->enmFmtGst, pabDst, (uint32_t)cbDst, &cbRead);
505 RTTEST_CHECK_MSG(g_hTest, vrc2 == VINF_SUCCESS, (g_hTest, "Got %Rrc, expected VINF_SUCCESS\n", vrc2));
506 RTTEST_CHECK_MSG(g_hTest, cbRead == cbToRead, (g_hTest, "Read %RU32 bytes, expected %zu\n", cbRead, cbToRead));
507
508 if (pTask->enmFmtGst == VBOX_SHCL_FMT_UNICODETEXT)
509 RTTEST_CHECK_MSG(g_hTest, RTUtf16ValidateEncoding((PRTUTF16)pabDst) == VINF_SUCCESS, (g_hTest, "Read data is not valid UTF-16\n"));
510 if (cbRead == cbToRead)
511 {
512#ifndef RT_OS_WINDOWS /** @todo Not sure about OS/2. */
513 PRTUTF16 pwszSrc = NULL;
514 RTTEST_CHECK(g_hTest, RT_SUCCESS(RTStrToUtf16((const char *)pTask->pvData, &pwszSrc)));
515 RTTEST_CHECK_MSG(g_hTest, memcmp(pwszSrc, pabDst, cbRead) == 0, (g_hTest, "Read data does not match host data\n"));
516 RTUtf16Free(pwszSrc);
517#else
518 RTTEST_CHECK_MSG(g_hTest, memcmp(pTask->pvData, pabDst, cbRead) == 0, (g_hTest, "Read data does not match host data\n"));
519#endif
520 }
521
522 RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Read data from host:\n%.*Rhxd\n", cbRead, pabDst);
523
524 RTMemFree(pabDst);
525
526 return VINF_SUCCESS;
527}
528
529static DECLCALLBACK(int) tstTestReadFromHost_ThreadGuest(PTSTHGCMUTILSCTX pCtx, void *pvCtx)
530{
531 RTThreadSleep(1000); /* Fudge; wait until the host has prepared the data for the clipboard. */
532
533 PCLIPBOARDTESTCTX pTstCtx = (PCLIPBOARDTESTCTX)pvCtx;
534 AssertPtr(pTstCtx);
535
536 RT_ZERO(pTstCtx->Guest.CmdCtx);
537 RTTEST_CHECK_RC_OK(g_hTest, VbglR3ClipboardConnectEx(&pTstCtx->Guest.CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID));
538
539 RTThreadSleep(1000); /* Fudge; wait until the host has prepared the data for the clipboard. */
540
541 PCLIPBOARDTESTTASK pTstTask = (PCLIPBOARDTESTTASK)pCtx->Task.pvUser;
542 AssertPtr(pTstTask);
543 tstTestReadFromHost_DoIt(pTstCtx, pTstTask);
544
545 /* Signal that the task ended. */
546 TstHGCMUtilsTaskSignal(&pCtx->Task, VINF_SUCCESS);
547
548 RTTEST_CHECK_RC_OK(g_hTest, VbglR3ClipboardDisconnectEx(&pTstCtx->Guest.CmdCtx));
549
550 return VINF_SUCCESS;
551}
552
553static DECLCALLBACK(int) tstTestReadFromHost_ClientConnectedCallback(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient,
554 void *pvUser)
555{
556 RT_NOREF(pCtx, pClient);
557
558 PCLIPBOARDTESTCTX pTstCtx = (PCLIPBOARDTESTCTX)pvUser;
559 AssertPtr(pTstCtx); RT_NOREF(pTstCtx);
560
561 RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Client %RU32 connected\n", pClient->idClient);
562 return VINF_SUCCESS;
563}
564
565static DECLCALLBACK(int) tstTestReadFromHostSetup(PCLIPBOARDTESTCTX pTstCtx, void **ppvCtx)
566{
567 RT_NOREF(ppvCtx);
568
569 /* Set the right clipboard mode, so that the guest can read from the host. */
570 tstClipboardSetMode(TstHgcmMockSvcInst(), VBOX_SHCL_MODE_BIDIRECTIONAL);
571
572 /* Start the host thread first, so that the guest thread can connect to it later. */
573 TSTHGCMUTILSHOSTCALLBACKS HostCallbacks;
574 RT_ZERO(HostCallbacks);
575 HostCallbacks.pfnOnClientConnected = tstTestReadFromHost_ClientConnectedCallback;
576 TstHGCMUtilsHostThreadStart(&pTstCtx->HGCM, &HostCallbacks, pTstCtx /* pvUser */);
577
578 PCLIPBOARDTESTTASK pTask = &pTstCtx->Task;
579 AssertPtr(pTask);
580 pTask->enmFmtGst = VBOX_SHCL_FMT_UNICODETEXT;
581 pTask->enmFmtHst = pTask->enmFmtGst;
582 pTask->cbChunk = RTRandU32Ex(1, 512);
583 pTask->cbData = RT_ALIGN_32(pTask->cbChunk * RTRandU32Ex(1, 16), 2);
584 Assert(pTask->cbData % sizeof(RTUTF16) == 0);
585#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
586 pTask->pvData = tstGenerateUtf8StringA(pTask->cbData);
587 pTask->cbData++; /* Add terminating zero. */
588#else
589 pTask->pvData = tstGenerateUtf16StringA((uint32_t)(pTask->cbData /* We use bytes == chars here */));
590 pTask->cbData *= sizeof(RTUTF16);
591 pTask->cbData += sizeof(RTUTF16); /* Add terminating zero. */
592#endif
593 pTask->cbProcessed = 0;
594
595 int rc = VINF_SUCCESS;
596
597#if defined (RT_OS_LINUX) || defined (RT_OS_SOLARIS)
598 /* Initialize the Shared Clipboard backend callbacks. */
599 PSHCLBACKEND pBackend = ShClSvcGetBackend();
600
601 SHCLCALLBACKS ShClCallbacks;
602 RT_ZERO(ShClCallbacks);
603 ShClCallbacks.pfnReportFormats = tstTestReadFromHost_ReportFormatsCallback;
604 ShClCallbacks.pfnOnClipboardRead = tstTestReadFromHost_OnClipboardReadCallback;
605 ShClBackendSetCallbacks(pBackend, &ShClCallbacks);
606#elif defined (RT_OS_WINDOWS)
607 rc = ShClWinOpen(GetDesktopWindow());
608 if (RT_SUCCESS(rc))
609 {
610 rc = ShClWinDataWrite(CF_UNICODETEXT, pTask->pvData, (uint32_t)pTask->cbData);
611 ShClWinClose();
612 }
613#endif /* defined (RT_OS_LINUX) || defined (RT_OS_SOLARIS) */
614
615 RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Host data (%RU32):\n%.*Rhxd\n", pTask->cbData, pTask->cbData, pTask->pvData);
616 return rc;
617}
618
619static DECLCALLBACK(int) tstTestReadFromHostExec(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx)
620{
621 RT_NOREF(pvCtx);
622
623 TstHGCMUtilsGuestThreadStart(&pTstCtx->HGCM, tstTestReadFromHost_ThreadGuest, pTstCtx);
624
625 PTSTHGCMUTILSTASK pTask = (PTSTHGCMUTILSTASK)TstHGCMUtilsTaskGetCurrent(&pTstCtx->HGCM);
626
627 bool fUseMock = false;
628 TSTUSERMOCK UsrMock;
629 if (fUseMock)
630 tstTestReadFromHost_MockInit(&UsrMock, "tstX11Hst");
631
632 /* Wait until the task has been finished. */
633 TstHGCMUtilsTaskWait(pTask, RT_MS_30SEC);
634
635 if (fUseMock)
636 tstTestReadFromHost_MockDestroy(&UsrMock);
637
638 return VINF_SUCCESS;
639}
640
641static DECLCALLBACK(int) tstTestReadFromHostDestroy(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx)
642{
643 RT_NOREF(pvCtx);
644
645 int vrc = TstHGCMUtilsGuestThreadStop(&pTstCtx->HGCM);
646 AssertRC(vrc);
647 vrc = TstHGCMUtilsHostThreadStop(&pTstCtx->HGCM);
648 AssertRC(vrc);
649
650 return vrc;
651}
652
653
654/*********************************************************************************************************************************
655* Main *
656*********************************************************************************************************************************/
657
658/** Test definition table. */
659CLIPBOARDTESTDESC g_aTests[] =
660{
661 /* Tests guest reading clipboard data from the host. */
662 { tstTestReadFromHostSetup, tstTestReadFromHostExec, tstTestReadFromHostDestroy }
663};
664/** Number of tests defined. */
665unsigned g_cTests = RT_ELEMENTS(g_aTests);
666
667static int tstOne(PTESTDESC pTstDesc)
668{
669 PCLIPBOARDTESTCTX pTstCtx = &g_TstCtx;
670
671 void *pvCtx;
672 int rc = pTstDesc->pfnSetup(pTstCtx, &pvCtx);
673 if (RT_SUCCESS(rc))
674 {
675 rc = pTstDesc->pfnExec(pTstCtx, pvCtx);
676
677 int rc2 = pTstDesc->pfnDestroy(pTstCtx, pvCtx);
678 if (RT_SUCCESS(rc))
679 rc = rc2;
680 }
681
682 return rc;
683}
684
685int main()
686{
687 /*
688 * Init the runtime, test and say hello.
689 */
690 RTEXITCODE rcExit = RTTestInitAndCreate("tstClipboardMockHGCM", &g_hTest);
691 if (rcExit != RTEXITCODE_SUCCESS)
692 return rcExit;
693 RTTestBanner(g_hTest);
694
695 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
696 TstHgcmMockSvcCreate(pSvc);
697 TstHgcmMockSvcStart(pSvc);
698
699 /*
700 * Run the tests.
701 */
702 if (0) /** @todo triggers assertion */
703 testGuestSimple();
704 if (1)
705 testHostCall();
706
707 RT_ZERO(g_TstCtx);
708
709 PTSTHGCMUTILSCTX pCtx = &g_TstCtx.HGCM;
710 TstHGCMUtilsCtxInit(pCtx, pSvc);
711
712 PTSTHGCMUTILSTASK pTask = (PTSTHGCMUTILSTASK)TstHGCMUtilsTaskGetCurrent(pCtx);
713 TstHGCMUtilsTaskInit(pTask);
714 pTask->pvUser = &g_TstCtx.Task;
715
716 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
717 tstOne(&g_aTests[i]);
718
719 TstHGCMUtilsTaskDestroy(pTask);
720
721 TstHgcmMockSvcStop(pSvc);
722 TstHgcmMockSvcDestroy(pSvc);
723
724 /*
725 * Summary
726 */
727 return RTTestSummaryAndDestroy(g_hTest);
728}
729
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