VirtualBox

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

Last change on this file since 105745 was 104317, checked in by vboxsync, 8 months ago

Shared Clipboard/Transfers: ShClTransferRootsInitFromXXX() -> ShClTransferRootsSetFromXXX(). bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/* $Id: tstClipboardTransfers.cpp 104317 2024-04-12 14:11:08Z vboxsync $ */
2/** @file
3 * Shared Clipboard transfers test case.
4 */
5
6/*
7 * Copyright (C) 2019-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#include "../VBoxSharedClipboardSvc-internal.h"
29
30#include <VBox/HostServices/VBoxClipboardSvc.h>
31
32#include <iprt/assert.h>
33#include <iprt/dir.h>
34#include <iprt/file.h>
35#include <iprt/path.h>
36#include <iprt/string.h>
37#include <iprt/test.h>
38
39
40static int testCreateTempDir(RTTEST hTest, const char *pszTestcase, char *pszTempDir, size_t cbTempDir)
41{
42 char szTempDir[RTPATH_MAX];
43 int rc = RTPathTemp(szTempDir, sizeof(szTempDir));
44 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
45
46 rc = RTPathAppend(szTempDir, sizeof(szTempDir), "tstClipboardTransfers");
47 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
48
49 rc = RTDirCreate(szTempDir, 0700, 0);
50 if (rc == VERR_ALREADY_EXISTS)
51 rc = VINF_SUCCESS;
52 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
53
54 rc = RTPathAppend(szTempDir, sizeof(szTempDir), "XXXXX");
55 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
56
57 rc = RTDirCreateTemp(szTempDir, 0700);
58 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
59
60 rc = RTPathJoin(pszTempDir, cbTempDir, szTempDir, pszTestcase);
61 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
62
63 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Created temporary directory: %s\n", pszTempDir);
64
65 return rc;
66}
67
68static int testRemoveTempDir(RTTEST hTest)
69{
70 char szTempDir[RTPATH_MAX];
71 int rc = RTPathTemp(szTempDir, sizeof(szTempDir));
72 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
73
74 rc = RTPathAppend(szTempDir, sizeof(szTempDir), "tstClipboardTransfers");
75 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
76
77 rc = RTDirRemoveRecursive(szTempDir, RTDIRRMREC_F_CONTENT_AND_DIR);
78 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
79
80 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Removed temporary directory: %s\n", szTempDir);
81
82 return rc;
83}
84
85static int testCreateDir(RTTEST hTest, const char *pszPathToCreate)
86{
87 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Creating directory: %s\n", pszPathToCreate);
88
89 int rc = RTDirCreateFullPath(pszPathToCreate, 0700);
90 if (rc == VERR_ALREADY_EXISTS)
91 rc = VINF_SUCCESS;
92 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
93
94 return rc;
95}
96
97static int testCreateFile(RTTEST hTest, const char *pszTempDir, const char *pszFileName, uint32_t fOpen, size_t cbSize,
98 char **ppszFilePathAbs)
99{
100 char szFilePath[RTPATH_MAX];
101
102 int rc = RTStrCopy(szFilePath, sizeof(szFilePath), pszTempDir);
103 RTTESTI_CHECK_RC_OK_RET(rc, rc);
104
105 rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszFileName);
106 RTTESTI_CHECK_RC_OK_RET(rc, rc);
107
108 char *pszDirToCreate = RTStrDup(szFilePath);
109 RTTESTI_CHECK_RET(pszDirToCreate, VERR_NO_MEMORY);
110
111 RTPathStripFilename(pszDirToCreate);
112
113 rc = testCreateDir(hTest, pszDirToCreate);
114 RTTESTI_CHECK_RC_OK_RET(rc, rc);
115
116 RTStrFree(pszDirToCreate);
117 pszDirToCreate = NULL;
118
119 if (!fOpen)
120 fOpen = RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE;
121
122 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Creating file: %s\n", szFilePath);
123
124 RTFILE hFile;
125 rc = RTFileOpen(&hFile, szFilePath, fOpen);
126 if (RT_SUCCESS(rc))
127 {
128 if (cbSize)
129 {
130 /** @todo Fill in some random stuff. */
131 }
132
133 rc = RTFileClose(hFile);
134 RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc);
135 }
136
137 if (ppszFilePathAbs)
138 *ppszFilePathAbs = RTStrDup(szFilePath);
139
140 return rc;
141}
142
143typedef struct TESTTRANSFERROOTENTRY
144{
145 TESTTRANSFERROOTENTRY(const RTCString &a_strPath)
146 : strPath(a_strPath) { }
147
148 RTCString strPath;
149} TESTTRANSFERROOTENTRY;
150
151static int testAddRootEntry(RTTEST hTest, const char *pszTempDir,
152 const TESTTRANSFERROOTENTRY &rootEntry, char **ppszRoots)
153{
154 char *pszRoots = NULL;
155
156 const char *pszPath = rootEntry.strPath.c_str();
157
158 char *pszPathAbs;
159 int rc = testCreateFile(hTest, pszTempDir, pszPath, 0, 0, &pszPathAbs);
160 RTTESTI_CHECK_RC_OK_RET(rc, rc);
161
162 rc = RTStrAAppend(&pszRoots, pszPathAbs);
163 RTTESTI_CHECK_RC_OK(rc);
164
165 rc = RTStrAAppend(&pszRoots, "\r\n");
166 RTTESTI_CHECK_RC_OK(rc);
167
168 RTStrFree(pszPathAbs);
169
170 *ppszRoots = pszRoots;
171
172 return rc;
173}
174
175static int testAddRootEntries(RTTEST hTest, const char *pszTempDir,
176 RTCList<TESTTRANSFERROOTENTRY> &lstBase, RTCList<TESTTRANSFERROOTENTRY> lstToExtend,
177 char **ppszRoots)
178{
179 int rc = VINF_SUCCESS;
180
181 char *pszRoots = NULL;
182
183 for (size_t i = 0; i < lstBase.size(); ++i)
184 {
185 char *pszEntry = NULL;
186 rc = testAddRootEntry(hTest, pszTempDir, lstBase.at(i), &pszEntry);
187 RTTESTI_CHECK_RC_OK_BREAK(rc);
188 rc = RTStrAAppend(&pszRoots, pszEntry);
189 RTTESTI_CHECK_RC_OK_BREAK(rc);
190 RTStrFree(pszEntry);
191 }
192
193 for (size_t i = 0; i < lstToExtend.size(); ++i)
194 {
195 char *pszEntry = NULL;
196 rc = testAddRootEntry(hTest, pszTempDir, lstToExtend.at(i), &pszEntry);
197 RTTESTI_CHECK_RC_OK_BREAK(rc);
198 rc = RTStrAAppend(&pszRoots, pszEntry);
199 RTTESTI_CHECK_RC_OK_BREAK(rc);
200 RTStrFree(pszEntry);
201 }
202
203 if (RT_SUCCESS(rc))
204 *ppszRoots = pszRoots;
205
206 return rc;
207}
208
209static void testTransferRootsSetSingle(RTTEST hTest,
210 RTCList<TESTTRANSFERROOTENTRY> &lstBase, RTCList<TESTTRANSFERROOTENTRY> lstToExtend,
211 int rcExpected)
212{
213 PSHCLTRANSFER pTransfer;
214 int rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, NULL /* Callbacks */, &pTransfer);
215 RTTESTI_CHECK_RC_OK(rc);
216
217 SHCLTXPROVIDER Provider;
218 RTTESTI_CHECK(ShClTransferProviderLocalQueryInterface(&Provider) != NULL);
219 RTTESTI_CHECK_RC_OK(ShClTransferSetProvider(pTransfer, &Provider));
220
221 char szTestTransferRootsSetDir[RTPATH_MAX];
222 rc = testCreateTempDir(hTest, "testTransferRootsSet", szTestTransferRootsSetDir, sizeof(szTestTransferRootsSetDir));
223 RTTESTI_CHECK_RC_OK_RETV(rc);
224
225 /* This is the file we're trying to access (but not supposed to). */
226 rc = testCreateFile(hTest, szTestTransferRootsSetDir, "must-not-access-this", 0, 0, NULL);
227 RTTESTI_CHECK_RC_OK(rc);
228
229 char *pszRoots;
230 rc = testAddRootEntries(hTest, szTestTransferRootsSetDir, lstBase, lstToExtend, &pszRoots);
231 RTTESTI_CHECK_RC_OK_RETV(rc);
232
233 rc = ShClTransferRootsSetFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1);
234 RTTESTI_CHECK_RC(rc, rcExpected);
235
236 RTStrFree(pszRoots);
237
238 rc = ShClTransferDestroy(pTransfer);
239 RTTESTI_CHECK_RC_OK(rc);
240}
241
242static void testTransferObjOpenSingle(RTTEST hTest,
243 RTCList<TESTTRANSFERROOTENTRY> &lstRoots, const char *pszObjPath, int rcExpected)
244{
245 PSHCLTRANSFER pTransfer;
246 int rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, NULL /* Callbacks */, &pTransfer);
247 RTTESTI_CHECK_RC_OK(rc);
248
249 SHCLTXPROVIDER Provider;
250 ShClTransferProviderLocalQueryInterface(&Provider);
251
252 rc = ShClTransferSetProvider(pTransfer, &Provider);
253 RTTESTI_CHECK_RC_OK(rc);
254
255 char szTestTransferObjOpenDir[RTPATH_MAX];
256 rc = testCreateTempDir(hTest, "testTransferObjOpen", szTestTransferObjOpenDir, sizeof(szTestTransferObjOpenDir));
257 RTTESTI_CHECK_RC_OK_RETV(rc);
258
259 /* This is the file we're trying to access (but not supposed to). */
260 rc = testCreateFile(hTest, szTestTransferObjOpenDir, "file1.txt", 0, 0, NULL);
261 RTTESTI_CHECK_RC_OK(rc);
262
263 RTCList<TESTTRANSFERROOTENTRY> lstToExtendEmpty;
264
265 char *pszRoots;
266 rc = testAddRootEntries(hTest, szTestTransferObjOpenDir, lstRoots, lstToExtendEmpty, &pszRoots);
267 RTTESTI_CHECK_RC_OK_RETV(rc);
268
269 rc = ShClTransferRootsSetFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1);
270 RTTESTI_CHECK_RC_OK(rc);
271
272 rc = ShClTransferInit(pTransfer);
273 RTTESTI_CHECK_RC_OK(rc);
274
275 RTStrFree(pszRoots);
276
277 SHCLOBJOPENCREATEPARMS openCreateParms;
278 rc = ShClTransferObjOpenParmsInit(&openCreateParms);
279 RTTESTI_CHECK_RC_OK(rc);
280
281 rc = RTStrCopy(openCreateParms.pszPath, openCreateParms.cbPath, pszObjPath);
282 RTTESTI_CHECK_RC_OK(rc);
283
284 SHCLOBJHANDLE hObj;
285 rc = ShClTransferObjOpen(pTransfer, &openCreateParms, &hObj);
286 RTTESTI_CHECK_RC(rc, rcExpected);
287 if (RT_SUCCESS(rc))
288 {
289 rc = ShClTransferObjClose(pTransfer, hObj);
290 RTTESTI_CHECK_RC_OK(rc);
291 }
292
293 ShClTransferObjOpenParmsDestroy(&openCreateParms);
294
295 rc = ShClTransferDestroy(pTransfer);
296 RTTESTI_CHECK_RC_OK(rc);
297}
298
299static void testEvents(void)
300{
301 RTTestISub("Testing events");
302
303 SHCLEVENTSOURCE Source;
304 RTTESTI_CHECK_RC_OK(ShClEventSourceCreate(&Source, 0));
305 RTTESTI_CHECK(ShClEventSourceGetLast(&Source) == NULL); /* Should be empty. */
306 RTTESTI_CHECK_RC_OK(ShClEventSourceDestroy(&Source));
307 RTTESTI_CHECK_RC_OK(ShClEventSourceDestroy(&Source)); /* Destroying a second time, intentional. */
308
309 RTTESTI_CHECK_RC_OK(ShClEventSourceCreate(&Source, 42));
310 PSHCLEVENT pEvent;
311 RTTESTI_CHECK_RC_OK(ShClEventSourceGenerateAndRegisterEvent(&Source, &pEvent));
312 ShClEventSourceReset(&Source);
313 RTTESTI_CHECK(ShClEventSourceGetLast(&Source) == NULL); /* Event still valid, but removed from the source. */
314 RTTESTI_CHECK(ShClEventRelease(pEvent) == 0); /* Free'd event, as ref count is 0. */
315 RTTESTI_CHECK(ShClEventSourceGetLast(&Source) == NULL); /* Now it should be empty. */
316 RTTESTI_CHECK_RC_OK(ShClEventSourceDestroy(&Source));
317
318 /* Test delayed destruction of the event by retaining it. */
319 RTTESTI_CHECK_RC_OK(ShClEventSourceCreate(&Source, 42));
320 RTTESTI_CHECK_RC_OK(ShClEventSourceGenerateAndRegisterEvent(&Source, &pEvent));
321 RTTESTI_CHECK_RC_OK(ShClEventRetain(pEvent));
322 RTTESTI_CHECK(ShClEventGetRefs(pEvent) == 2);
323 RTTESTI_CHECK_RC_OK(ShClEventSourceDestroy(&Source));
324 RTTESTI_CHECK(ShClEventGetRefs(pEvent) == 2); /* Make sure the ref count didn't drop due to ShClEventSourceDestroy(). */
325 RTTESTI_CHECK(ShClEventRelease(pEvent) == 1);
326 RTTESTI_CHECK(ShClEventGetRefs(pEvent) == 1);
327 RTTESTI_CHECK(ShClEventRelease(pEvent) == 0); /* Free'd event, as ref count is 0. */
328 RTTESTI_CHECK_RC_OK(ShClEventSourceDestroy(&Source)); /* Try to destruct again. */
329}
330
331static void testTransferBasics(void)
332{
333 RTTestISub("Testing transfer basics");
334
335 PSHCLTRANSFER pTransfer;
336 int rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, NULL /* Callbacks */, &pTransfer);
337 RTTESTI_CHECK_RC_OK(rc);
338 rc = ShClTransferDestroy(pTransfer);
339 RTTESTI_CHECK_RC_OK(rc);
340 pTransfer = NULL; /* Was free'd above. */
341 rc = ShClTransferDestroy(pTransfer); /* Second time, intentional. */
342 RTTESTI_CHECK_RC_OK(rc);
343
344 PSHCLLIST pList = ShClTransferListAlloc();
345 RTTESTI_CHECK(pList != NULL);
346 rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, NULL /* Callbacks */, &pTransfer);
347 RTTESTI_CHECK_RC_OK(rc);
348 ShClTransferListFree(pList);
349 pList = NULL;
350 ShClTransferListFree(pList); /* Second time, intentional. */
351
352 SHCLLISTENTRY Entry;
353 RTTESTI_CHECK_RC_OK(ShClTransferListEntryInit(&Entry));
354 ShClTransferListEntryDestroy(&Entry);
355 ShClTransferListEntryDestroy(&Entry); /* Second time, intentional. */
356
357 rc = ShClTransferDestroy(pTransfer);
358 RTTESTI_CHECK_RC_OK(rc);
359}
360
361static void testTransferRootsSet(RTTEST hTest)
362{
363 RTTestISub("Testing setting transfer roots");
364
365 /* Define the (valid) transfer root set. */
366 RTCList<TESTTRANSFERROOTENTRY> lstBase;
367 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/file1.txt"));
368 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/file1.txt"));
369 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/sub1/file1.txt"));
370 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/file1.txt"));
371 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/sub1/file1.txt"));
372
373 RTCList<TESTTRANSFERROOTENTRY> lstBreakout;
374 testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VINF_SUCCESS);
375
376 lstBreakout.clear();
377 lstBase.append(TESTTRANSFERROOTENTRY("../must-not-access-this"));
378 testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER);
379
380 lstBreakout.clear();
381 lstBase.append(TESTTRANSFERROOTENTRY("does-not-exist/file1.txt"));
382 testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER);
383
384 lstBreakout.clear();
385 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/../must-not-access-this"));
386 testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER);
387
388 lstBreakout.clear();
389 lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/./../must-not-access-this"));
390 testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER);
391
392 lstBreakout.clear();
393 lstBase.append(TESTTRANSFERROOTENTRY("../does-not-exist"));
394 testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER);
395}
396
397static void testTransferObjOpen(RTTEST hTest)
398{
399 RTTestISub("Testing setting transfer object open");
400
401 /* Define the (valid) transfer root set. */
402 RTCList<TESTTRANSFERROOTENTRY> lstRoots;
403 lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/file1.txt"));
404 lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/file1.txt"));
405 lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/sub1/file1.txt"));
406 lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/file1.txt"));
407 lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/sub1/file1.txt"));
408
409 testTransferObjOpenSingle(hTest, lstRoots, "file1.txt", VINF_SUCCESS);
410 testTransferObjOpenSingle(hTest, lstRoots, "does-not-exist.txt", VERR_PATH_NOT_FOUND);
411 testTransferObjOpenSingle(hTest, lstRoots, "dir1/does-not-exist.txt", VERR_PATH_NOT_FOUND);
412 testTransferObjOpenSingle(hTest, lstRoots, "../must-not-access-this.txt", VERR_INVALID_PARAMETER);
413 testTransferObjOpenSingle(hTest, lstRoots, "dir1/../../must-not-access-this.txt", VERR_INVALID_PARAMETER);
414}
415
416int main(int argc, char *argv[])
417{
418 /*
419 * Init the runtime, test and say hello.
420 */
421 const char *pcszExecName;
422 NOREF(argc);
423 pcszExecName = strrchr(argv[0], '/');
424 pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0];
425 RTTEST hTest;
426 RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &hTest);
427 if (rcExit != RTEXITCODE_SUCCESS)
428 return rcExit;
429 RTTestBanner(hTest);
430
431 /* For negative stuff that may assert: */
432 bool const fMayPanic = RTAssertSetMayPanic(false);
433 bool const fQuiet = RTAssertSetQuiet(true);
434
435 testEvents();
436 testTransferBasics();
437 testTransferRootsSet(hTest);
438 testTransferObjOpen(hTest);
439
440 int rc = testRemoveTempDir(hTest);
441 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
442
443 RTAssertSetMayPanic(fMayPanic);
444 RTAssertSetQuiet(fQuiet);
445
446 /*
447 * Summary
448 */
449 return RTTestSummaryAndDestroy(hTest);
450}
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