VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

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