summaryrefslogtreecommitdiffstats
path: root/src/VBox/GuestHost/DragAndDrop/testcase
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/GuestHost/DragAndDrop/testcase
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/GuestHost/DragAndDrop/testcase')
-rw-r--r--src/VBox/GuestHost/DragAndDrop/testcase/Makefile.kmk81
-rw-r--r--src/VBox/GuestHost/DragAndDrop/testcase/tstDnDPath.cpp100
-rw-r--r--src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferList.cpp206
-rw-r--r--src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferObject.cpp128
-rw-r--r--src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/Makefile.kmk53
-rw-r--r--src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/tstDragAndDropQt.cpp67
6 files changed, 635 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/DragAndDrop/testcase/Makefile.kmk b/src/VBox/GuestHost/DragAndDrop/testcase/Makefile.kmk
new file mode 100644
index 00000000..05568ce3
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/testcase/Makefile.kmk
@@ -0,0 +1,81 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the DnD testcases.
+#
+
+#
+# Copyright (C) 2020-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK)
+
+ if defined(VBOX_WITH_QTGUI)
+ include $(PATH_SUB_CURRENT)/tstDragAndDropQt/Makefile.kmk
+ endif
+
+ PROGRAMS += tstDnDTransferObject tstDnDTransferList tstDnDPath
+ TESTING += \
+ $(tstDnDTransferObject_0_OUTDIR)/tstDnDTransferObject.run \
+ $(tstDnDTransferList_0_OUTDIR)/tstDnDTransferList.run \
+ $(tstDnDTransferPath_0_OUTDIR)/tstDnDPath.run
+
+ tstDnDTransferObject_TEMPLATE = VBoxR3TstExe
+ tstDnDTransferObject_DEFS = UNIT_TEST TESTCASE
+ tstDnDTransferObject_SOURCES = \
+ tstDnDTransferObject.cpp \
+ ../DnDTransferObject.cpp \
+ ../DnDPath.cpp
+ tstDnDTransferObject_CLEAN = $(tstDnDTransferObject_0_OUTDIR)/tstDnDTransferObject.run
+
+ $$(tstDnDTransferObject_0_OUTDIR)/tstDnDTransferObject.run: $$(tstDnDTransferObject_1_STAGE_TARGET)
+ export VBOX_LOG_DEST=nofile; $(tstDnDTransferObject_1_STAGE_TARGET) quiet
+ $(QUIET)$(APPEND) -t "$@" "done"
+
+ tstDnDTransferList_TEMPLATE = VBoxR3TstExe
+ tstDnDTransferList_DEFS = UNIT_TEST TESTCASE
+ tstDnDTransferList_SOURCES = \
+ tstDnDTransferList.cpp \
+ ../DnDTransferObject.cpp \
+ ../DnDTransferList.cpp \
+ ../DnDPath.cpp
+ tstDnDTransferList_CLEAN = $(tstDnDTransferList_0_OUTDIR)/tstDnDTransferList.run
+
+ $$(tstDnDTransferList_0_OUTDIR)/tstDnDTransferList.run: $$(tstDnDTransferList_1_STAGE_TARGET)
+ export VBOX_LOG_DEST=nofile; $(tstDnDTransferList_1_STAGE_TARGET) quiet
+ $(QUIET)$(APPEND) -t "$@" "done"
+
+ tstDnDPath_TEMPLATE = VBoxR3TstExe
+ tstDnDPath_DEFS = UNIT_TEST TESTCASE
+ tstDnDPath_SOURCES = \
+ tstDnDPath.cpp \
+ ../DnDPath.cpp
+ tstDnDPath_CLEAN = $(tstDnDPath_0_OUTDIR)/tstDnDPath.run
+
+ $$(tstDnDPath_0_OUTDIR)/tstDnDPath.run: $$(tstDnDPath_1_STAGE_TARGET)
+ export VBOX_LOG_DEST=nofile; $(tstDnDPath_1_STAGE_TARGET) quiet
+ $(QUIET)$(APPEND) -t "$@" "done"
+
+endif
+
+include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDPath.cpp b/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDPath.cpp
new file mode 100644
index 00000000..8cface1b
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDPath.cpp
@@ -0,0 +1,100 @@
+/* $Id: tstDnDPath.cpp $ */
+/** @file
+ * DnD path tests.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/errcore.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+#include <VBox/GuestHost/DragAndDrop.h>
+
+
+static void tstPathRebase(RTTEST hTest)
+{
+ static struct
+ {
+ char const *pszPath;
+ char const *pszPathOld;
+ char const *pszPathNew;
+ int rc;
+ char const *pszResult;
+ } const s_aTests[] = {
+ /* Invalid stuff. */
+ { NULL, NULL, NULL, VERR_INVALID_POINTER, NULL },
+ { "foo", "old", NULL, VERR_INVALID_POINTER, NULL },
+ /* Actual rebasing. */
+ { "old/foo", "old", "new", VINF_SUCCESS, "new/foo" },
+ /* Note: DnDPathRebase intentionally does not do any path conversions. */
+#ifdef RT_OS_WINDOWS
+ { "old\\foo", "old", "new", VINF_SUCCESS, "new/foo" },
+ { "\\totally\\different\\path\\foo", "/totally/different/path", "/totally/different/path", VINF_SUCCESS, "/totally/different/path/foo" },
+ { "\\old\\path\\foo", "", "/new/root/", VINF_SUCCESS, "/new/root/old/path/foo" },
+ { "\\\\old\\path\\\\foo", "", "/new/root/", VINF_SUCCESS, "/new/root/old/path\\\\foo" }
+#else
+ { "old/foo", "old", "new", VINF_SUCCESS, "new/foo" },
+ { "/totally/different/path/foo", "/totally/different/path", "/totally/different/path", VINF_SUCCESS, "/totally/different/path/foo" },
+ { "/old/path/foo", "", "/new/root/", VINF_SUCCESS, "/new/root/old/path/foo" },
+ { "//old/path//foo", "", "/new/root/", VINF_SUCCESS, "/new/root/old/path//foo" }
+#endif
+ };
+
+ char *pszPath = NULL;
+ for (size_t i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ RTTestDisableAssertions(hTest);
+ RTTEST_CHECK_RC(hTest, DnDPathRebase(s_aTests[i].pszPath, s_aTests[i].pszPathOld, s_aTests[i].pszPathNew, &pszPath),
+ s_aTests[i].rc);
+ RTTestRestoreAssertions(hTest);
+ if (RT_SUCCESS(s_aTests[i].rc))
+ {
+ if (s_aTests[i].pszResult)
+ RTTEST_CHECK_MSG(hTest, RTPathCompare(pszPath, s_aTests[i].pszResult) == 0,
+ (hTest, "Test #%zu failed: Got '%s', expected '%s'", i, pszPath, s_aTests[i].pszResult));
+ RTStrFree(pszPath);
+ pszPath = NULL;
+ }
+ }
+}
+
+int main()
+{
+ /*
+ * Init the runtime, test and say hello.
+ */
+ RTTEST hTest;
+ int rc = RTTestInitAndCreate("tstDnDPath", &hTest);
+ if (rc)
+ return rc;
+ RTTestBanner(hTest);
+
+ tstPathRebase(hTest);
+
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferList.cpp b/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferList.cpp
new file mode 100644
index 00000000..164b6200
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferList.cpp
@@ -0,0 +1,206 @@
+/* $Id: tstDnDTransferList.cpp $ */
+/** @file
+ * DnD transfer list tests.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/err.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+#include <VBox/GuestHost/DragAndDrop.h>
+
+
+int main()
+{
+ /*
+ * Init the runtime, test and say hello.
+ */
+ RTTEST hTest;
+ int rc = RTTestInitAndCreate("tstDnDTransferList", &hTest);
+ if (rc)
+ return rc;
+ RTTestBanner(hTest);
+
+ char szPathWellKnown[RTPATH_MAX];
+ RTStrCopy(szPathWellKnown, sizeof(szPathWellKnown),
+#ifdef RT_OS_WINDOWS
+ "C:\\Windows\\System32\\Boot\\");
+#else
+ "/bin/");
+#endif
+
+ char szPathWellKnownURI[RTPATH_MAX];
+ RTStrPrintf(szPathWellKnownURI, sizeof(szPathWellKnownURI), "file:///%s", szPathWellKnown);
+
+ DNDTRANSFERLIST list;
+ RT_ZERO(list);
+
+ /* Invalid stuff. */
+ RTTestDisableAssertions(hTest);
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, "", DNDTRANSFERLISTFMT_NATIVE), VERR_INVALID_PARAMETER);
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, szPathWellKnown, DNDTRANSFERLISTFMT_NATIVE), VINF_SUCCESS);
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, szPathWellKnown, DNDTRANSFERLISTFMT_NATIVE), VERR_WRONG_ORDER);
+ RTTestRestoreAssertions(hTest);
+ DnDTransferListDestroy(&list);
+
+ /* Empty. */
+ RTTEST_CHECK_RC(hTest, DnDTransferListInit(&list), VINF_SUCCESS);
+ DnDTransferListDestroy(&list);
+
+ /* Initial status. */
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, szPathWellKnown, DNDTRANSFERLISTFMT_NATIVE), VINF_SUCCESS);
+ RTTEST_CHECK(hTest, DnDTransferListGetRootCount(&list) == 0);
+ RTTEST_CHECK(hTest, DnDTransferListObjCount(&list) == 0);
+ RTTEST_CHECK(hTest, DnDTransferListObjTotalBytes(&list) == 0);
+ RTTEST_CHECK(hTest, DnDTransferListObjGetFirst(&list) == NULL);
+ DnDTransferListDestroy(&list);
+
+ char szPathTest[RTPATH_MAX];
+
+ /* Root path handling. */
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, szPathWellKnown, DNDTRANSFERLISTFMT_NATIVE), VINF_SUCCESS);
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPath(&list, DNDTRANSFERLISTFMT_NATIVE, "/wrong/root/path", DNDTRANSFERLIST_FLAGS_NONE), VERR_INVALID_PARAMETER);
+ rc = RTPathJoin(szPathTest, sizeof(szPathTest), szPathWellKnown, "/non/existing");
+ AssertRCReturn(rc, RTEXITCODE_FAILURE);
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPath(&list, DNDTRANSFERLISTFMT_NATIVE, szPathTest, DNDTRANSFERLIST_FLAGS_NONE), VERR_PATH_NOT_FOUND);
+ DnDTransferListDestroy(&list);
+
+ /* Adding native stuff. */
+ /* No root path set yet and non-recursive -> will set root path to szPathWellKnown, but without any entries added. */
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, szPathWellKnown, DNDTRANSFERLISTFMT_NATIVE), VINF_SUCCESS);
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPath(&list, DNDTRANSFERLISTFMT_NATIVE, szPathWellKnown, DNDTRANSFERLIST_FLAGS_NONE), VINF_SUCCESS);
+ RTTEST_CHECK(hTest, DnDTransferListGetRootCount(&list));
+ RTTEST_CHECK(hTest, DnDTransferListObjCount(&list));
+
+ /* Add szPathWellKnown again, this time recursively. */
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPath(&list, DNDTRANSFERLISTFMT_NATIVE, szPathWellKnown, DNDTRANSFERLIST_FLAGS_RECURSIVE), VINF_SUCCESS);
+ RTTEST_CHECK(hTest, DnDTransferListGetRootCount(&list));
+ RTTEST_CHECK(hTest, DnDTransferListObjCount(&list));
+
+ char *pszString = NULL;
+ size_t cbString = 0;
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferListGetRoots(&list, DNDTRANSFERLISTFMT_NATIVE, &pszString, &cbString));
+ RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Roots:\n%s\n\n", pszString);
+ RTStrFree(pszString);
+
+ PDNDTRANSFEROBJECT pObj;
+ while ((pObj = DnDTransferListObjGetFirst(&list)))
+ {
+ RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Obj: %s\n", DnDTransferObjectGetDestPath(pObj));
+ DnDTransferListObjRemoveFirst(&list);
+ }
+ DnDTransferListDestroy(&list);
+
+ char *pszBuf;
+ size_t cbBuf;
+
+ /* To URI data. */
+ RTTEST_CHECK_RC(hTest, DnDTransferListInitEx(&list, szPathWellKnownURI, DNDTRANSFERLISTFMT_URI), VINF_SUCCESS);
+ RTStrPrintf(szPathTest, sizeof(szPathTest), "%s/foo", szPathWellKnownURI);
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPath(&list, DNDTRANSFERLISTFMT_URI, szPathWellKnownURI, DNDTRANSFERLIST_FLAGS_NONE), VINF_SUCCESS);
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPath(&list, DNDTRANSFERLISTFMT_URI, szPathTest, DNDTRANSFERLIST_FLAGS_NONE), VERR_PATH_NOT_FOUND);
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_NATIVE, "" /* pszBasePath */, "\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Roots (native):\n%s\n", pszBuf);
+ RTStrFree(pszBuf);
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_URI, "" /* pszBasePath */, "\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Roots (URI):\n%s\n", pszBuf);
+ RTStrFree(pszBuf);
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_URI, "\\new\\base\\path", "\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Roots (URI, new base):\n%s\n", pszBuf);
+ RTStrFree(pszBuf);
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_URI, "\\..\\invalid\\path", "\n", &pszBuf, &cbBuf), VERR_INVALID_PARAMETER);
+ DnDTransferListDestroy(&list);
+
+ /* From URI data. */
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ RTStrPrintf(szPathTest, sizeof(szPathTest), "C:/Windows/");
+ static const char s_szURI[] =
+ "file:///C:/Windows/System32/Boot/\r\n"
+ "file:///C:/Windows/System/\r\n";
+ static const char s_szURIFmtURI[] =
+ "file:///base/System32/Boot/\r\n"
+ "file:///base/System/\r\n";
+ static const char s_szURIFmtNative[] =
+ "\\base\\System32\\Boot\\\r\n"
+ "\\base\\System\\\r\n";
+#else
+ RTStrPrintf(szPathTest, sizeof(szPathTest), "/usr/");
+ static const char s_szURI[] =
+ "file:///usr/bin/\r\n"
+ "file:///usr/lib/\r\n";
+ static const char s_szURIFmtURI[] =
+ "file:///base/bin/\r\n"
+ "file:///base/lib/\r\n";
+ static const char s_szURIFmtNative[] =
+ "/base/bin/\r\n"
+ "/base/lib/\r\n";
+#endif
+
+ RTTEST_CHECK_RC(hTest, DnDTransferListAppendPathsFromBuffer(&list, DNDTRANSFERLISTFMT_URI, s_szURI, sizeof(s_szURI), "\r\n",
+ DNDTRANSFERLIST_FLAGS_NONE), VINF_SUCCESS);
+ RTTEST_CHECK(hTest, DnDTransferListGetRootCount(&list) == 2);
+ RTTEST_CHECK(hTest, RTPathCompare(DnDTransferListGetRootPathAbs(&list), szPathTest) == 0);
+
+ /* Validate returned lengths. */
+ pszBuf = NULL;
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_URI, "/base/", "\r\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTEST_CHECK_MSG(hTest, RTStrCmp(pszBuf, s_szURIFmtURI) == 0, (hTest, "Got '%s'", pszBuf));
+ RTTEST_CHECK_MSG(hTest, cbBuf == strlen(pszBuf) + 1, (hTest, "Got %d, expected %d\n", cbBuf, strlen(pszBuf) + 1));
+ RTStrFree(pszBuf);
+
+ pszBuf = NULL;
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_NATIVE, "/base/", "\r\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTEST_CHECK_MSG(hTest, RTStrCmp(pszBuf, s_szURIFmtNative) == 0,
+ (hTest, "Expected %.*Rhxs\nGot %.*Rhxs\n '%s'",
+ sizeof(s_szURIFmtNative) - 1, s_szURIFmtNative,
+ strlen(pszBuf), pszBuf, pszBuf));
+ RTTEST_CHECK_MSG(hTest, cbBuf == strlen(pszBuf) + 1, (hTest, "Got %d, expected %d\n", cbBuf, strlen(pszBuf) + 1));
+ RTStrFree(pszBuf);
+
+ /* Validate roots with a new base. */
+ pszBuf = NULL;
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_NATIVE, "/native/base/path", "\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Roots (URI, new base):\n%s\n", pszBuf);
+ RTStrFree(pszBuf);
+
+ pszBuf = NULL;
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_NATIVE, "\\windows\\path", "\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Roots (URI, new base):\n%s\n", pszBuf);
+ RTStrFree(pszBuf);
+
+ pszBuf = NULL;
+ RTTEST_CHECK_RC(hTest, DnDTransferListGetRootsEx(&list, DNDTRANSFERLISTFMT_NATIVE, "\\\\windows\\\\path", "\n", &pszBuf, &cbBuf), VINF_SUCCESS);
+ RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Roots (URI, new base):\n%s\n", pszBuf);
+ RTStrFree(pszBuf);
+
+ DnDTransferListDestroy(&list);
+ DnDTransferListDestroy(&list); /* Doing this twice here is intentional. */
+
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferObject.cpp b/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferObject.cpp
new file mode 100644
index 00000000..f887aac3
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/testcase/tstDnDTransferObject.cpp
@@ -0,0 +1,128 @@
+/* $Id: tstDnDTransferObject.cpp $ */
+/** @file
+ * DnD URI object (DNDTRANSFEROBJECT) tests.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/errcore.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+#include <VBox/GuestHost/DragAndDrop.h>
+
+
+static void tstPaths(RTTEST hTest)
+{
+ RTTestSub(hTest, "Testing path handling");
+
+ char szBuf[64];
+
+ DNDTRANSFEROBJECT Obj;
+ RT_ZERO(Obj);
+
+ /*
+ * Initialization handling.
+ */
+ RTTEST_CHECK(hTest, DnDTransferObjectGetSourcePath(&Obj) == NULL);
+ RTTEST_CHECK_RC(hTest, DnDTransferObjectGetDestPathEx(&Obj, DNDTRANSFEROBJPATHSTYLE_TRANSPORT, szBuf, sizeof(szBuf)), VERR_NOT_FOUND);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetMode(&Obj) == 0);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetSize(&Obj) == 0);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetProcessed(&Obj) == 0);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetType(&Obj) == DNDTRANSFEROBJTYPE_UNKNOWN);
+
+ /*
+ * Paths handling.
+ */
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_FILE, "", "/rel/path/to/dst"));
+ RTTestDisableAssertions(hTest);
+ RTTEST_CHECK_RC (hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_FILE, "", "/rel/path/to/dst"), VERR_WRONG_ORDER);
+ RTTestRestoreAssertions(hTest);
+ DnDTransferObjectReset(&Obj);
+
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_FILE, "/src/path1", "dst/path2"));
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetSourcePath(&Obj), "/src/path1/dst/path2") == 0);
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetDestPath(&Obj), "dst/path2") == 0);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetDestPathEx(&Obj, DNDTRANSFEROBJPATHSTYLE_DOS, szBuf, sizeof(szBuf)) == VINF_SUCCESS
+ && RTStrCmp(szBuf, "dst\\path2") == 0);
+ DnDTransferObjectReset(&Obj);
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_FILE, "", "dst/with/ending/slash/"));
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetDestPath(&Obj), "dst/with/ending/slash/") == 0);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetDestPathEx(&Obj, DNDTRANSFEROBJPATHSTYLE_TRANSPORT, szBuf, sizeof(szBuf)) == VINF_SUCCESS
+ && RTStrCmp(szBuf, "dst/with/ending/slash/") == 0);
+ DnDTransferObjectReset(&Obj);
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_DIRECTORY, "", "dst/path2"));
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetSourcePath(&Obj), "dst/path2/") == 0);
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetDestPath(&Obj), "dst/path2/") == 0);
+ DnDTransferObjectReset(&Obj);
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_DIRECTORY, "", "dst\\to\\path2"));
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetSourcePath(&Obj), "dst/to/path2/") == 0);
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetDestPath(&Obj), "dst/to/path2/") == 0);
+ DnDTransferObjectReset(&Obj);
+ /* Test that the destination does not have a beginning slash. */
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_DIRECTORY, "/src/path2", "/dst/to/path2/"));
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetSourcePath(&Obj), "/src/path2/dst/to/path2/") == 0);
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetDestPath(&Obj), "dst/to/path2/") == 0);
+ DnDTransferObjectReset(&Obj);
+ RTTEST_CHECK_RC_OK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_DIRECTORY, "/src/path2", "//////dst/to/path2/"));
+ RTTEST_CHECK(hTest, RTStrCmp(DnDTransferObjectGetDestPath(&Obj), "dst/to/path2/") == 0);
+
+ /*
+ * Invalid stuff.
+ */
+ DnDTransferObjectReset(&Obj);
+ RTTestDisableAssertions(hTest);
+ RTTEST_CHECK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_DIRECTORY, "/src/path3", "../../dst/path3") == VERR_INVALID_PARAMETER);
+ RTTEST_CHECK(hTest, DnDTransferObjectInitEx(&Obj, DNDTRANSFEROBJTYPE_DIRECTORY, "/src/../../path3", "dst/path3") == VERR_INVALID_PARAMETER);
+ RTTestRestoreAssertions(hTest);
+
+ /*
+ * Reset handling.
+ */
+ DnDTransferObjectReset(&Obj);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetSourcePath(&Obj) == NULL);
+ RTTEST_CHECK(hTest, DnDTransferObjectGetDestPath(&Obj) == NULL);
+
+ DnDTransferObjectDestroy(&Obj);
+ DnDTransferObjectDestroy(&Obj); /* Doing this twice here is intentional. */
+}
+
+int main()
+{
+ /*
+ * Init the runtime, test and say hello.
+ */
+ RTTEST hTest;
+ int rc = RTTestInitAndCreate("tstDnDTransferObject", &hTest);
+ if (rc)
+ return rc;
+ RTTestBanner(hTest);
+
+ tstPaths(hTest);
+
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/Makefile.kmk b/src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/Makefile.kmk
new file mode 100644
index 00000000..4e3d8795
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/Makefile.kmk
@@ -0,0 +1,53 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for tstDragAndDropQt.
+#
+
+#
+# Copyright (C) 2022-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# Targets and units.
+#
+USES += qt5
+PROGRAMS.linux += tstDragAndDropQt # Just needed for Linux right now.
+
+#
+# tstDragAndDropQt
+#
+tstDragAndDropQt_TEMPLATE = VBoxQtGuiExe
+tstDragAndDropQt_DEFS = UNIT_TEST TESTCASE
+tstDragAndDropQt_NAME = tstDragAndDropQt
+tstDragAndDropQt_CXXFLAGS = \
+ $(VBOX_GCC_Wno-implicit-fallthrough) \
+ $(VBOX_GCC_Wno-deprecated-declarations)
+
+tstDragAndDropQt_SOURCES = \
+ tstDragAndDropQt.cpp
+
+# The Qt modules we're using.
+tstDragAndDropQt_QT_MODULES = Core Gui Widgets PrintSupport
+
+include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/tstDragAndDropQt.cpp b/src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/tstDragAndDropQt.cpp
new file mode 100644
index 00000000..0d7a6144
--- /dev/null
+++ b/src/VBox/GuestHost/DragAndDrop/testcase/tstDragAndDropQt/tstDragAndDropQt.cpp
@@ -0,0 +1,67 @@
+/* $Id: tstDragAndDropQt.cpp $ */
+/** @file
+ * Drag and drop Qt code test cases.
+ */
+
+/*
+ * Copyright (C) 2022-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <QtWidgets>
+
+class DnDWin : public QWidget
+{
+ public:
+
+ explicit DnDWin(QWidget *parent = nullptr) : QWidget(parent)
+ {
+ setMinimumSize(400, 400);
+ setWindowTitle("Drag me!");
+ setAcceptDrops(true);
+ }
+
+ void mouseMoveEvent(QMouseEvent *event)
+ {
+ if(!(event->buttons() & Qt::LeftButton))
+ return DnDWin::mouseMoveEvent(event);
+
+ event->accept();
+
+ QDrag *drag = new QDrag(this);
+
+ QMimeData *mime = new QMimeData();
+ mime->setData("text/plain", QString("/tmp/%1").arg("foo.bar").toLatin1());
+ mime->setData("text/uri-list", QString("file:///tmp/%1").arg("foo.bar").toLatin1());
+
+ drag->setMimeData(mime);
+ drag->exec();
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ DnDWin win;
+ win.show();
+
+ app.exec();
+}