VirtualBox

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

最後變更 在這個檔案從97392是 97283,由 vboxsync 提交於 2 年 前

Shared Clipboard/testcase: Make use of now-available SharedClipboardWinDataWrite() with the HGCM mocking framework on Windows. Also contains some Windows-related test data adjustments.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette