VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp@ 93969

Last change on this file since 93969 was 93919, checked in by vboxsync, 3 years ago

Shared Clipboard: Resolved a @todo (renamed ShClBackendFormatAnnounce -> ShClBackendReportFormats).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1/* $Id: tstClipboardServiceHost.cpp 93919 2022-02-24 13:59:11Z vboxsync $ */
2/** @file
3 * Shared Clipboard host service test case.
4 */
5
6/*
7 * Copyright (C) 2011-2022 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 "../VBoxSharedClipboardSvc-internal.h"
19
20#include <VBox/HostServices/VBoxClipboardSvc.h>
21
22#include <iprt/assert.h>
23#include <iprt/string.h>
24#include <iprt/test.h>
25
26extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
27
28static SHCLCLIENT g_Client;
29static VBOXHGCMSVCHELPERS g_Helpers = { NULL };
30
31/** Simple call handle structure for the guest call completion callback */
32struct VBOXHGCMCALLHANDLE_TYPEDEF
33{
34 /** Where to store the result code */
35 int32_t rc;
36};
37
38/** Call completion callback for guest calls. */
39static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
40{
41 callHandle->rc = rc;
42 return VINF_SUCCESS;
43}
44
45static int setupTable(VBOXHGCMSVCFNTABLE *pTable)
46{
47 pTable->cbSize = sizeof(*pTable);
48 pTable->u32Version = VBOX_HGCM_SVC_VERSION;
49 g_Helpers.pfnCallComplete = callComplete;
50 pTable->pHelpers = &g_Helpers;
51 return VBoxHGCMSvcLoad(pTable);
52}
53
54static void testSetMode(void)
55{
56 struct VBOXHGCMSVCPARM parms[2];
57 VBOXHGCMSVCFNTABLE table;
58 uint32_t u32Mode;
59 int rc;
60
61 RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_MODE");
62 rc = setupTable(&table);
63 RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc));
64
65 /* Reset global variable which doesn't reset itself. */
66 HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_OFF);
67 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
68 RTTESTI_CHECK_RC_OK(rc);
69 u32Mode = ShClSvcGetMode();
70 RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_OFF, ("u32Mode=%u\n", (unsigned) u32Mode));
71
72 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 0, parms);
73 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
74
75 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 2, parms);
76 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
77
78 HGCMSvcSetU64(&parms[0], 99);
79 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
80 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
81
82 HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_HOST_TO_GUEST);
83 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
84 RTTESTI_CHECK_RC_OK(rc);
85 u32Mode = ShClSvcGetMode();
86 RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_HOST_TO_GUEST, ("u32Mode=%u\n", (unsigned) u32Mode));
87
88 HGCMSvcSetU32(&parms[0], 99);
89 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
90 RTTESTI_CHECK_RC(rc, VERR_NOT_SUPPORTED);
91
92 u32Mode = ShClSvcGetMode();
93 RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_OFF, ("u32Mode=%u\n", (unsigned) u32Mode));
94 table.pfnUnload(NULL);
95}
96
97#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
98static void testSetTransferMode(void)
99{
100 struct VBOXHGCMSVCPARM parms[2];
101 VBOXHGCMSVCFNTABLE table;
102
103 RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE");
104 int rc = setupTable(&table);
105 RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc));
106
107 /* Invalid parameter. */
108 HGCMSvcSetU64(&parms[0], 99);
109 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
110 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
111
112 /* Invalid mode. */
113 HGCMSvcSetU32(&parms[0], 99);
114 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
115 RTTESTI_CHECK_RC(rc, VERR_INVALID_FLAGS);
116
117 /* Enable transfers. */
118 HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_ENABLED);
119 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
120 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
121
122 /* Disable transfers again. */
123 HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_DISABLED);
124 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms);
125 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
126}
127#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
128
129/* Adds a host data read request message to the client's message queue. */
130static void testMsgAddReadData(PSHCLCLIENT pClient, SHCLFORMATS fFormats)
131{
132 int rc = ShClSvcGuestDataRequest(pClient, fFormats, NULL /* pidEvent */);
133 RTTESTI_CHECK_RC_OK(rc);
134}
135
136/* Does testing of VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, needed for providing compatibility to older Guest Additions clients. */
137static void testGetHostMsgOld(void)
138{
139 struct VBOXHGCMSVCPARM parms[2];
140 VBOXHGCMSVCFNTABLE table;
141 VBOXHGCMCALLHANDLE_TYPEDEF call;
142 int rc;
143
144 RTTestISub("Setting up VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT test");
145 rc = setupTable(&table);
146 RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc));
147 /* Unless we are bidirectional the host message requests will be dropped. */
148 HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_BIDIRECTIONAL);
149 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms);
150 RTTESTI_CHECK_RC_OK(rc);
151
152
153 RTTestISub("Testing one format, waiting guest call.");
154 RT_ZERO(g_Client);
155 HGCMSvcSetU32(&parms[0], 0);
156 HGCMSvcSetU32(&parms[1], 0);
157 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
158 table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0);
159 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
160 RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This should get updated only when the guest call completes. */
161 testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_UNICODETEXT);
162 RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA);
163 RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_UNICODETEXT);
164 RTTESTI_CHECK_RC_OK(call.rc);
165 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
166 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
167 RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */
168 table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client);
169
170 RTTestISub("Testing one format, no waiting guest calls.");
171 RT_ZERO(g_Client);
172 table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0);
173 testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_HTML);
174 HGCMSvcSetU32(&parms[0], 0);
175 HGCMSvcSetU32(&parms[1], 0);
176 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
177 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
178 RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA);
179 RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_HTML);
180 RTTESTI_CHECK_RC_OK(call.rc);
181 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
182 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
183 RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */
184 table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client);
185
186 RTTestISub("Testing two formats, waiting guest call.");
187 RT_ZERO(g_Client);
188 table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0);
189 HGCMSvcSetU32(&parms[0], 0);
190 HGCMSvcSetU32(&parms[1], 0);
191 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
192 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
193 RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This should get updated only when the guest call completes. */
194 testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_HTML);
195 RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA);
196 RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_UNICODETEXT);
197 RTTESTI_CHECK_RC_OK(call.rc);
198 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
199 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
200 RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA);
201 RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_HTML);
202 RTTESTI_CHECK_RC_OK(call.rc);
203 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
204 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
205 RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */
206 table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client);
207
208 RTTestISub("Testing two formats, no waiting guest calls.");
209 RT_ZERO(g_Client);
210 table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0);
211 testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_HTML);
212 HGCMSvcSetU32(&parms[0], 0);
213 HGCMSvcSetU32(&parms[1], 0);
214 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
215 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
216 RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA);
217 RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_UNICODETEXT);
218 RTTESTI_CHECK_RC_OK(call.rc);
219 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
220 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
221 RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA);
222 RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_HTML);
223 RTTESTI_CHECK_RC_OK(call.rc);
224 call.rc = VERR_IPE_UNINITIALIZED_STATUS;
225 table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0);
226 RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */
227 table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client);
228 table.pfnUnload(NULL);
229}
230
231static void testSetHeadless(void)
232{
233 struct VBOXHGCMSVCPARM parms[2];
234 VBOXHGCMSVCFNTABLE table;
235 bool fHeadless;
236 int rc;
237
238 RTTestISub("Testing HOST_FN_SET_HEADLESS");
239 rc = setupTable(&table);
240 RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc));
241 /* Reset global variable which doesn't reset itself. */
242 HGCMSvcSetU32(&parms[0], false);
243 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS,
244 1, parms);
245 RTTESTI_CHECK_RC_OK(rc);
246 fHeadless = ShClSvcGetHeadless();
247 RTTESTI_CHECK_MSG(fHeadless == false, ("fHeadless=%RTbool\n", fHeadless));
248 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS,
249 0, parms);
250 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
251 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS,
252 2, parms);
253 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
254 HGCMSvcSetU64(&parms[0], 99);
255 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS,
256 1, parms);
257 RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER);
258 HGCMSvcSetU32(&parms[0], true);
259 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS,
260 1, parms);
261 RTTESTI_CHECK_RC_OK(rc);
262 fHeadless = ShClSvcGetHeadless();
263 RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless));
264 HGCMSvcSetU32(&parms[0], 99);
265 rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS,
266 1, parms);
267 RTTESTI_CHECK_RC_OK(rc);
268 fHeadless = ShClSvcGetHeadless();
269 RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless));
270 table.pfnUnload(NULL);
271}
272
273static void testHostCall(void)
274{
275 testSetMode();
276#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
277 testSetTransferMode();
278#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
279 testSetHeadless();
280}
281
282int main(int argc, char *argv[])
283{
284 /*
285 * Init the runtime, test and say hello.
286 */
287 const char *pcszExecName;
288 NOREF(argc);
289 pcszExecName = strrchr(argv[0], '/');
290 pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0];
291 RTTEST hTest;
292 RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &hTest);
293 if (rcExit != RTEXITCODE_SUCCESS)
294 return rcExit;
295 RTTestBanner(hTest);
296
297 /* Don't let assertions in the host service panic (core dump) the test cases. */
298 RTAssertSetMayPanic(false);
299
300 /*
301 * Run the tests.
302 */
303 testHostCall();
304 testGetHostMsgOld();
305
306 /*
307 * Summary
308 */
309 return RTTestSummaryAndDestroy(hTest);
310}
311
312int ShClBackendInit(PSHCLBACKEND, VBOXHGCMSVCFNTABLE *) { return VINF_SUCCESS; }
313void ShClBackendDestroy(PSHCLBACKEND) { }
314int ShClBackendDisconnect(PSHCLBACKEND, PSHCLCLIENT) { return VINF_SUCCESS; }
315int ShClBackendConnect(PSHCLBACKEND, PSHCLCLIENT, bool) { return VINF_SUCCESS; }
316int ShClBackendReportFormats(PSHCLBACKEND, PSHCLCLIENT, SHCLFORMATS) { AssertFailed(); return VINF_SUCCESS; }
317int ShClBackendReadData(PSHCLBACKEND, PSHCLCLIENT, PSHCLCLIENTCMDCTX, SHCLFORMAT, void *, uint32_t, unsigned int *) { AssertFailed(); return VERR_WRONG_ORDER; }
318int ShClBackendWriteData(PSHCLBACKEND, PSHCLCLIENT, PSHCLCLIENTCMDCTX, SHCLFORMAT, void *, uint32_t) { AssertFailed(); return VINF_SUCCESS; }
319int ShClBackendSync(PSHCLBACKEND, PSHCLCLIENT) { return VINF_SUCCESS; }
320
321#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
322int ShClBackendTransferCreate(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
323int ShClBackendTransferDestroy(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
324int ShClBackendTransferGetRoots(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
325#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
326
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