diff options
Diffstat (limited to 'src/VBox/HostServices/SharedClipboard/testcase')
10 files changed, 2159 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedClipboard/testcase/.scm-settings b/src/VBox/HostServices/SharedClipboard/testcase/.scm-settings new file mode 100644 index 00000000..0da8323c --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/.scm-settings @@ -0,0 +1,29 @@ +# $Id: .scm-settings $ +## @file +# Source code massager settings for the host HGCM services. +# + +# +# Copyright (C) 2019-2022 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 +# + +--filter-out-files *.txt +/*.h: --guard-relative-to-dir . diff --git a/src/VBox/HostServices/SharedClipboard/testcase/Makefile.kmk b/src/VBox/HostServices/SharedClipboard/testcase/Makefile.kmk new file mode 100644 index 00000000..90bd18a8 --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/Makefile.kmk @@ -0,0 +1,147 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the Shared Clipboard Host Service testcases. +# + +# +# Copyright (C) 2011-2022 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) + +# +# Testcase which mocks HGCM to also test the VbglR3-side of Shared Clipboard. +# +# Goal is to use and test as much guest side code as possible as a self-contained +# binary on the host here. +# +# Note: No #ifdef TESTCASE hacks or similar allowed, has to run +# without #ifdef modifications to the core code! +# +tstClipboardMockHGCM_TEMPLATE = VBOXR3TSTEXE +tstClipboardMockHGCM_DEFS = VBOX_WITH_HGCM VBOX_WITH_SHARED_CLIPBOARD +tstClipboardMockHGCM_SOURCES = \ + ../VBoxSharedClipboardSvc.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp \ + $(PATH_ROOT)/src/VBox/HostServices/common/message.cpp \ + tstClipboardMockHGCM.cpp +tstClipboardMockHGCM_LIBS = $(LIB_RUNTIME) + +if1of ($(KBUILD_TARGET), linux solaris) + PROGRAMS += tstClipboardMockHGCM + tstClipboardMockHGCM_SOURCES += \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp \ + ../VBoxSharedClipboardSvc-x11.cpp + tstClipboardMockHGCM_LIBPATH = \ + $(VBOX_LIBPATH_X11) + tstClipboardMockHGCM_LIBS += \ + Xt \ + X11 +endif +if1of ($(KBUILD_TARGET), win) + PROGRAMS += tstClipboardMockHGCM + tstClipboardMockHGCM_SOURCES += \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp \ + ../VBoxSharedClipboardSvc-win.cpp +endif + +tstClipboardMockHGCM_CLEAN = $(tstClipboardMockHGCM_0_OUTDIR)/tstClipboardMockHGCM.run + +if defined(VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS) + tstClipboardMockHGCM_DEFS += VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + tstClipboardMockHGCM_SOURCES += \ + ../VBoxSharedClipboardSvc-transfers.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp +endif + +if 0 # Enable this if you want automatic runs after compilation. + $$(tstClipboardMockHGCM_0_OUTDIR)/tstClipboardMockHGCM.run: $$(tstClipboardMockHGCM_1_STAGE_TARGET) + export VBOX_LOG_DEST=nofile; $(tstClipboardMockHGCM_1_STAGE_TARGET) quiet + $(QUIET)$(APPEND) -t "$@" "done" + OTHERS += $(tstClipboardMockHGCM_0_OUTDIR)/tstClipboardMockHGCM.run +endif + + # + # + # + PROGRAMS += tstClipboardServiceHost + tstClipboardServiceHost_TEMPLATE = VBOXR3TSTEXE + tstClipboardServiceHost_DEFS = VBOX_WITH_HGCM UNIT_TEST + tstClipboardServiceHost_SOURCES = \ + ../VBoxSharedClipboardSvc.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \ + $(PATH_ROOT)/src/VBox/HostServices/common/message.cpp \ + tstClipboardServiceHost.cpp + tstClipboardServiceHost_LIBS = $(LIB_RUNTIME) + tstClipboardServiceHost_CLEAN = $(tstClipboardServiceHost_0_OUTDIR)/tstClipboardServiceHost.run + + if defined(VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS) + tstClipboardServiceHost_DEFS += VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + tstClipboardServiceHost_SOURCES += \ + ../VBoxSharedClipboardSvc-transfers.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp + endif + + # + # + # + PROGRAMS += tstClipboardServiceImpl + tstClipboardServiceImpl_TEMPLATE = VBOXR3TSTEXE + tstClipboardServiceImpl_DEFS = VBOX_WITH_HGCM UNIT_TEST + tstClipboardServiceImpl_SOURCES = \ + ../VBoxSharedClipboardSvc.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \ + $(PATH_ROOT)/src/VBox/HostServices/common/message.cpp \ + tstClipboardServiceImpl.cpp + tstClipboardServiceImpl_SOURCES.win = \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp + tstClipboardServiceImpl_LIBS = $(LIB_RUNTIME) + tstClipboardServiceImpl_CLEAN = $(tstClipboardServiceImpl_0_OUTDIR)/tstClipboardServiceImpl.run + + if defined(VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS) + # + # + # + PROGRAMS += tstClipboardTransfers + tstClipboardTransfers_TEMPLATE = VBOXR3TSTEXE + tstClipboardTransfers_DEFS = VBOX_WITH_HGCM UNIT_TEST VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + tstClipboardTransfers_SOURCES = \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp \ + tstClipboardTransfers.cpp + endif +endif + +# +# List of above testcases that will be included in the ValKit. +# +ifdef VBOX_WITH_VALIDATIONKIT_UNITTESTS_PACKING + if1of ($(KBUILD_TARGET), linux solaris win) + VALKIT_UNITTESTS_WHITELIST_GUEST_ADDITIONS += \ + tstClipboardMockHGCM + endif +endif # VBOX_WITH_VALIDATIONKIT_UNITTESTS_PACKING + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgCfHtml1.h b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgCfHtml1.h new file mode 100644 index 00000000..e5272887 --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgCfHtml1.h @@ -0,0 +1,165 @@ +/* $Id: VBoxOrgCfHtml1.h $ */ +/** @file + * Shared Clipboard host service test case C data file of VBoxOrgCfHtml1.txt. + */ + +/* + * Copyright (C) 2022 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 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxOrgCfHtml1_h +#define VBOX_INCLUDED_SRC_VBoxOrgCfHtml1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +const unsigned char g_abVBoxOrgCfHtml1[] = +{ + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x2e, 0x39, 0x0d, 0x0a, 0x53, 0x74, 0x61, /* 0x00000000: Version:0.9..Sta */ + 0x72, 0x74, 0x48, 0x54, 0x4d, 0x4c, 0x3a, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x34, /* 0x00000010: rtHTML:000000014 */ + 0x34, 0x0d, 0x0a, 0x45, 0x6e, 0x64, 0x48, 0x54, 0x4d, 0x4c, 0x3a, 0x30, 0x30, 0x30, 0x30, 0x30, /* 0x00000020: 4..EndHTML:00000 */ + 0x30, 0x31, 0x39, 0x36, 0x31, 0x0d, 0x0a, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x72, 0x61, 0x67, /* 0x00000030: 01961..StartFrag */ + 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x38, 0x30, 0x0d, /* 0x00000040: ment:0000000180. */ + 0x0a, 0x45, 0x6e, 0x64, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x30, 0x30, 0x30, /* 0x00000050: .EndFragment:000 */ + 0x30, 0x30, 0x30, 0x31, 0x39, 0x32, 0x35, 0x0d, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, /* 0x00000060: 0001925..SourceU */ + 0x52, 0x4c, 0x3a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, /* 0x00000070: RL:https:..www.v */ + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x0d, 0x0a, /* 0x00000080: irtualbox.org... */ + 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x0d, 0x0a, /* 0x00000090: <html>..<body>.. */ + 0x3c, 0x21, 0x2d, 0x2d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, /* 0x000000a0: <!--StartFragmen */ + 0x74, 0x2d, 0x2d, 0x3e, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, /* 0x000000b0: t--><span style= */ + 0x22, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x30, 0x2c, 0x20, 0x30, /* 0x000000c0: "color: rgb(0, 0 */ + 0x2c, 0x20, 0x30, 0x29, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, /* 0x000000d0: , 0); font-famil */ + 0x79, 0x3a, 0x20, 0x56, 0x65, 0x72, 0x64, 0x61, 0x6e, 0x61, 0x2c, 0x20, 0x26, 0x71, 0x75, 0x6f, /* 0x000000e0: y: Verdana, &quo */ + 0x74, 0x3b, 0x42, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x56, 0x65, 0x72, 0x61, /* 0x000000f0: t;Bitstream Vera */ + 0x20, 0x53, 0x61, 0x6e, 0x73, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x2c, 0x20, 0x73, 0x61, 0x6e, /* 0x00000100: Sans", san */ + 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, /* 0x00000110: s-serif; font-si */ + 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x33, 0x70, 0x78, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, /* 0x00000120: ze: 13px; font-s */ + 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, /* 0x00000130: tyle: normal; fo */ + 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x6c, 0x69, 0x67, 0x61, 0x74, /* 0x00000140: nt-variant-ligat */ + 0x75, 0x72, 0x65, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, /* 0x00000150: ures: normal; fo */ + 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x63, 0x61, 0x70, 0x73, 0x3a, /* 0x00000160: nt-variant-caps: */ + 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, /* 0x00000170: normal; font-we */ + 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x30, 0x30, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, /* 0x00000180: ight: 400; lette */ + 0x72, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, /* 0x00000190: r-spacing: norma */ + 0x6c, 0x3b, 0x20, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x74, /* 0x000001a0: l; orphans: 2; t */ + 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, /* 0x000001b0: ext-align: start */ + 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x69, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x30, /* 0x000001c0: ; text-indent: 0 */ + 0x70, 0x78, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, /* 0x000001d0: px; text-transfo */ + 0x72, 0x6d, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2d, /* 0x000001e0: rm: none; white- */ + 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x77, /* 0x000001f0: space: normal; w */ + 0x69, 0x64, 0x6f, 0x77, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x77, 0x6f, 0x72, 0x64, 0x2d, 0x73, /* 0x00000200: idows: 2; word-s */ + 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x2d, 0x77, 0x65, /* 0x00000210: pacing: 0px; -we */ + 0x62, 0x6b, 0x69, 0x74, 0x2d, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x6f, 0x6b, 0x65, /* 0x00000220: bkit-text-stroke */ + 0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x62, 0x61, 0x63, /* 0x00000230: -width: 0px; bac */ + 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, /* 0x00000240: kground-color: r */ + 0x67, 0x62, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, /* 0x00000250: gb(255, 255, 255 */ + 0x29, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, /* 0x00000260: ); text-decorati */ + 0x6f, 0x6e, 0x2d, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, 0x73, 0x3a, 0x20, 0x69, 0x6e, /* 0x00000270: on-thickness: in */ + 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, /* 0x00000280: itial; text-deco */ + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x69, 0x6e, /* 0x00000290: ration-style: in */ + 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, /* 0x000002a0: itial; text-deco */ + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x69, 0x6e, /* 0x000002b0: ration-color: in */ + 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, /* 0x000002c0: itial; display: */ + 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x21, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6e, /* 0x000002d0: inline !importan */ + 0x74, 0x3b, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x22, /* 0x000002e0: t; float: none;" */ + 0x3e, 0x53, 0x65, 0x65, 0x20, 0x22, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x3c, 0x61, 0x20, /* 0x000002f0: >See "<.span><a */ + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x77, 0x69, 0x6b, 0x69, 0x22, 0x20, 0x68, 0x72, 0x65, /* 0x00000300: class="wiki" hre */ + 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, /* 0x00000310: f="https:..www.v */ + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x69, /* 0x00000320: irtualbox.org.wi */ + 0x6b, 0x69, 0x2f, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x22, 0x20, 0x73, /* 0x00000330: ki.VirtualBox" s */ + 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, /* 0x00000340: tyle="text-decor */ + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x63, 0x6f, 0x6c, /* 0x00000350: ation: none; col */ + 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x39, /* 0x00000360: or: rgb(0, 0, 19 */ + 0x32, 0x29, 0x3b, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x62, 0x6f, 0x74, 0x74, 0x6f, /* 0x00000370: 2); border-botto */ + 0x6d, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, /* 0x00000380: m: none; font-fa */ + 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x20, 0x56, 0x65, 0x72, 0x64, 0x61, 0x6e, 0x61, 0x2c, 0x20, 0x26, /* 0x00000390: mily: Verdana, & */ + 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x42, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x56, /* 0x000003a0: quot;Bitstream V */ + 0x65, 0x72, 0x61, 0x20, 0x53, 0x61, 0x6e, 0x73, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x2c, 0x20, /* 0x000003b0: era Sans", */ + 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, /* 0x000003c0: sans-serif; font */ + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x33, 0x70, 0x78, 0x3b, 0x20, 0x66, 0x6f, 0x6e, /* 0x000003d0: -size: 13px; fon */ + 0x74, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, /* 0x000003e0: t-style: normal; */ + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x6c, 0x69, /* 0x000003f0: font-variant-li */ + 0x67, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, /* 0x00000400: gatures: normal; */ + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x63, 0x61, /* 0x00000410: font-variant-ca */ + 0x70, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, /* 0x00000420: ps: normal; font */ + 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x30, 0x30, 0x3b, 0x20, 0x6c, 0x65, /* 0x00000430: -weight: 400; le */ + 0x74, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x6e, 0x6f, /* 0x00000440: tter-spacing: no */ + 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x73, 0x3a, 0x20, 0x32, /* 0x00000450: rmal; orphans: 2 */ + 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x73, 0x74, /* 0x00000460: ; text-align: st */ + 0x61, 0x72, 0x74, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x69, 0x6e, 0x64, 0x65, 0x6e, 0x74, /* 0x00000470: art; text-indent */ + 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, /* 0x00000480: : 0px; text-tran */ + 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x77, 0x68, 0x69, /* 0x00000490: sform: none; whi */ + 0x74, 0x65, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, /* 0x000004a0: te-space: normal */ + 0x3b, 0x20, 0x77, 0x69, 0x64, 0x6f, 0x77, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x77, 0x6f, 0x72, /* 0x000004b0: ; widows: 2; wor */ + 0x64, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, /* 0x000004c0: d-spacing: 0px; */ + 0x2d, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2d, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x73, 0x74, 0x72, /* 0x000004d0: -webkit-text-str */ + 0x6f, 0x6b, 0x65, 0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, /* 0x000004e0: oke-width: 0px; */ + 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, /* 0x000004f0: background-color */ + 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, /* 0x00000500: : rgb(255, 255, */ + 0x32, 0x35, 0x35, 0x29, 0x3b, 0x22, 0x3e, 0x41, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x56, 0x69, 0x72, /* 0x00000510: 255);">About Vir */ + 0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x73, 0x70, 0x61, 0x6e, /* 0x00000520: tualBox<.a><span */ + 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, /* 0x00000530: style="color: r */ + 0x67, 0x62, 0x28, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x29, 0x3b, 0x20, 0x66, 0x6f, 0x6e, /* 0x00000540: gb(0, 0, 0); fon */ + 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x20, 0x56, 0x65, 0x72, 0x64, 0x61, 0x6e, /* 0x00000550: t-family: Verdan */ + 0x61, 0x2c, 0x20, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x42, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, /* 0x00000560: a, "Bitstre */ + 0x61, 0x6d, 0x20, 0x56, 0x65, 0x72, 0x61, 0x20, 0x53, 0x61, 0x6e, 0x73, 0x26, 0x71, 0x75, 0x6f, /* 0x00000570: am Vera Sans&quo */ + 0x74, 0x3b, 0x2c, 0x20, 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3b, 0x20, /* 0x00000580: t;, sans-serif; */ + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x33, 0x70, 0x78, 0x3b, /* 0x00000590: font-size: 13px; */ + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, /* 0x000005a0: font-style: nor */ + 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, /* 0x000005b0: mal; font-varian */ + 0x74, 0x2d, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, /* 0x000005c0: t-ligatures: nor */ + 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, /* 0x000005d0: mal; font-varian */ + 0x74, 0x2d, 0x63, 0x61, 0x70, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, /* 0x000005e0: t-caps: normal; */ + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x30, 0x30, /* 0x000005f0: font-weight: 400 */ + 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, /* 0x00000600: ; letter-spacing */ + 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, /* 0x00000610: : normal; orphan */ + 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, /* 0x00000620: s: 2; text-align */ + 0x3a, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x69, 0x6e, /* 0x00000630: : start; text-in */ + 0x64, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, /* 0x00000640: dent: 0px; text- */ + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, /* 0x00000650: transform: none; */ + 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x6e, 0x6f, /* 0x00000660: white-space: no */ + 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x77, 0x69, 0x64, 0x6f, 0x77, 0x73, 0x3a, 0x20, 0x32, 0x3b, /* 0x00000670: rmal; widows: 2; */ + 0x20, 0x77, 0x6f, 0x72, 0x64, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, /* 0x00000680: word-spacing: 0 */ + 0x70, 0x78, 0x3b, 0x20, 0x2d, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2d, 0x74, 0x65, 0x78, 0x74, /* 0x00000690: px; -webkit-text */ + 0x2d, 0x73, 0x74, 0x72, 0x6f, 0x6b, 0x65, 0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, /* 0x000006a0: -stroke-width: 0 */ + 0x70, 0x78, 0x3b, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, /* 0x000006b0: px; background-c */ + 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, /* 0x000006c0: olor: rgb(255, 2 */ + 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x29, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, /* 0x000006d0: 55, 255); text-d */ + 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, /* 0x000006e0: ecoration-thickn */ + 0x65, 0x73, 0x73, 0x3a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x74, 0x65, /* 0x000006f0: ess: initial; te */ + 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73, 0x74, /* 0x00000700: xt-decoration-st */ + 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x74, 0x65, /* 0x00000710: yle: initial; te */ + 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, /* 0x00000720: xt-decoration-co */ + 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x64, 0x69, /* 0x00000730: lor: initial; di */ + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x21, 0x69, /* 0x00000740: splay: inline !i */ + 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6e, 0x74, 0x3b, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, /* 0x00000750: mportant; float: */ + 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x22, 0x3e, 0x22, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6e, /* 0x00000760: none;">" for an */ + 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x3c, 0x2f, /* 0x00000770: introduction.<. */ + 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x3c, 0x21, 0x2d, 0x2d, 0x45, 0x6e, 0x64, 0x46, 0x72, 0x61, 0x67, /* 0x00000780: span><!--EndFrag */ + 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x2d, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, /* 0x00000790: ment-->..<.body> */ + 0x0d, 0x0a, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x00, /* 0x000007a0: ..<.html>. */ +}; + +const unsigned g_cbVBoxOrgCfHtml1 = sizeof(g_abVBoxOrgCfHtml1); + +#endif /* !VBOX_INCLUDED_SRC_VBoxOrgCfHtml1_h */ diff --git a/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgCfHtml1.txt b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgCfHtml1.txt Binary files differnew file mode 100644 index 00000000..39a83822 --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgCfHtml1.txt diff --git a/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgMimeHtml1.h b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgMimeHtml1.h new file mode 100644 index 00000000..55c15af0 --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgMimeHtml1.h @@ -0,0 +1,152 @@ +/* $Id: VBoxOrgMimeHtml1.h $ */ +/** @file + * Shared Clipboard host service test case C data file of VBoxOrgMimeHtml1.txt. + */ + +/* + * Copyright (C) 2022 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 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxOrgMimeHtml1_h +#define VBOX_INCLUDED_SRC_VBoxOrgMimeHtml1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/cdefs.h> + +const unsigned char g_abVBoxOrgMimeHtml1[] = +{ + 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x63, 0x6f, 0x6c, /* 0x00000000: <span style="col */ + 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x29, /* 0x00000010: or: rgb(0, 0, 0) */ + 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x20, 0x56, /* 0x00000020: ; font-family: V */ + 0x65, 0x72, 0x64, 0x61, 0x6e, 0x61, 0x2c, 0x20, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x42, 0x69, /* 0x00000030: erdana, "Bi */ + 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x56, 0x65, 0x72, 0x61, 0x20, 0x53, 0x61, 0x6e, /* 0x00000040: tstream Vera San */ + 0x73, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x2c, 0x20, 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, /* 0x00000050: s", sans-se */ + 0x72, 0x69, 0x66, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, /* 0x00000060: rif; font-size: */ + 0x31, 0x33, 0x70, 0x78, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, /* 0x00000070: 13px; font-style */ + 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, /* 0x00000080: : normal; font-v */ + 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, /* 0x00000090: ariant-ligatures */ + 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, /* 0x000000a0: : normal; font-v */ + 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x63, 0x61, 0x70, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, /* 0x000000b0: ariant-caps: nor */ + 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, /* 0x000000c0: mal; font-weight */ + 0x3a, 0x20, 0x34, 0x30, 0x30, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x70, /* 0x000000d0: : 400; letter-sp */ + 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x6f, /* 0x000000e0: acing: normal; o */ + 0x72, 0x70, 0x68, 0x61, 0x6e, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, /* 0x000000f0: rphans: 2; text- */ + 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x3b, 0x20, 0x74, 0x65, /* 0x00000100: align: start; te */ + 0x78, 0x74, 0x2d, 0x69, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, /* 0x00000110: xt-indent: 0px; */ + 0x74, 0x65, 0x78, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x20, /* 0x00000120: text-transform: */ + 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2d, 0x73, 0x70, 0x61, 0x63, /* 0x00000130: none; white-spac */ + 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x77, 0x69, 0x64, 0x6f, 0x77, /* 0x00000140: e: normal; widow */ + 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x77, 0x6f, 0x72, 0x64, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, /* 0x00000150: s: 2; word-spaci */ + 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x2d, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, /* 0x00000160: ng: 0px; -webkit */ + 0x2d, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x6f, 0x6b, 0x65, 0x2d, 0x77, 0x69, 0x64, /* 0x00000170: -text-stroke-wid */ + 0x74, 0x68, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, /* 0x00000180: th: 0px; backgro */ + 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x32, /* 0x00000190: und-color: rgb(2 */ + 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x29, 0x3b, 0x20, 0x74, /* 0x000001a0: 55, 255, 255); t */ + 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x74, /* 0x000001b0: ext-decoration-t */ + 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, 0x73, 0x3a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, /* 0x000001c0: hickness: initia */ + 0x6c, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, /* 0x000001d0: l; text-decorati */ + 0x6f, 0x6e, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, /* 0x000001e0: on-style: initia */ + 0x6c, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, /* 0x000001f0: l; text-decorati */ + 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, /* 0x00000200: on-color: initia */ + 0x6c, 0x3b, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, 0x69, /* 0x00000210: l; display: inli */ + 0x6e, 0x65, 0x20, 0x21, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6e, 0x74, 0x3b, 0x20, 0x66, /* 0x00000220: ne !important; f */ + 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x22, 0x3e, 0x53, 0x65, 0x65, /* 0x00000230: loat: none;">See */ + 0x20, 0x22, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x3c, 0x61, 0x20, 0x63, 0x6c, 0x61, 0x73, /* 0x00000240: "<.span><a clas */ + 0x73, 0x3d, 0x22, 0x77, 0x69, 0x6b, 0x69, 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, /* 0x00000250: s="wiki" href="h */ + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x72, 0x74, 0x75, /* 0x00000260: ttps:..www.virtu */ + 0x61, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x69, 0x6b, 0x69, 0x2f, 0x56, /* 0x00000270: albox.org.wiki.V */ + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x22, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, /* 0x00000280: irtualBox" style */ + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, /* 0x00000290: ="text-decoratio */ + 0x6e, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, /* 0x000002a0: n: none; color: */ + 0x72, 0x67, 0x62, 0x28, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x39, 0x32, 0x29, 0x3b, 0x20, /* 0x000002b0: rgb(0, 0, 192); */ + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x3a, 0x20, 0x6e, /* 0x000002c0: border-bottom: n */ + 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, /* 0x000002d0: one; font-family */ + 0x3a, 0x20, 0x56, 0x65, 0x72, 0x64, 0x61, 0x6e, 0x61, 0x2c, 0x20, 0x26, 0x71, 0x75, 0x6f, 0x74, /* 0x000002e0: : Verdana, " */ + 0x3b, 0x42, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x56, 0x65, 0x72, 0x61, 0x20, /* 0x000002f0: ;Bitstream Vera */ + 0x53, 0x61, 0x6e, 0x73, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x2c, 0x20, 0x73, 0x61, 0x6e, 0x73, /* 0x00000300: Sans", sans */ + 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, /* 0x00000310: -serif; font-siz */ + 0x65, 0x3a, 0x20, 0x31, 0x33, 0x70, 0x78, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x74, /* 0x00000320: e: 13px; font-st */ + 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, /* 0x00000330: yle: normal; fon */ + 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x75, /* 0x00000340: t-variant-ligatu */ + 0x72, 0x65, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, /* 0x00000350: res: normal; fon */ + 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x63, 0x61, 0x70, 0x73, 0x3a, 0x20, /* 0x00000360: t-variant-caps: */ + 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, /* 0x00000370: normal; font-wei */ + 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x30, 0x30, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, /* 0x00000380: ght: 400; letter */ + 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, /* 0x00000390: -spacing: normal */ + 0x3b, 0x20, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x74, 0x65, /* 0x000003a0: ; orphans: 2; te */ + 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x3b, /* 0x000003b0: xt-align: start; */ + 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x69, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x70, /* 0x000003c0: text-indent: 0p */ + 0x78, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, /* 0x000003d0: x; text-transfor */ + 0x6d, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2d, 0x73, /* 0x000003e0: m: none; white-s */ + 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x77, 0x69, /* 0x000003f0: pace: normal; wi */ + 0x64, 0x6f, 0x77, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x77, 0x6f, 0x72, 0x64, 0x2d, 0x73, 0x70, /* 0x00000400: dows: 2; word-sp */ + 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x2d, 0x77, 0x65, 0x62, /* 0x00000410: acing: 0px; -web */ + 0x6b, 0x69, 0x74, 0x2d, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x6f, 0x6b, 0x65, 0x2d, /* 0x00000420: kit-text-stroke- */ + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x62, 0x61, 0x63, 0x6b, /* 0x00000430: width: 0px; back */ + 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, /* 0x00000440: ground-color: rg */ + 0x62, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x29, /* 0x00000450: b(255, 255, 255) */ + 0x3b, 0x22, 0x3e, 0x41, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, /* 0x00000460: ;">About Virtual */ + 0x42, 0x6f, 0x78, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, /* 0x00000470: Box<.a><span sty */ + 0x6c, 0x65, 0x3d, 0x22, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x30, /* 0x00000480: le="color: rgb(0 */ + 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x29, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, /* 0x00000490: , 0, 0); font-fa */ + 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x20, 0x56, 0x65, 0x72, 0x64, 0x61, 0x6e, 0x61, 0x2c, 0x20, 0x26, /* 0x000004a0: mily: Verdana, & */ + 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x42, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x56, /* 0x000004b0: quot;Bitstream V */ + 0x65, 0x72, 0x61, 0x20, 0x53, 0x61, 0x6e, 0x73, 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x2c, 0x20, /* 0x000004c0: era Sans", */ + 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, /* 0x000004d0: sans-serif; font */ + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x33, 0x70, 0x78, 0x3b, 0x20, 0x66, 0x6f, 0x6e, /* 0x000004e0: -size: 13px; fon */ + 0x74, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, /* 0x000004f0: t-style: normal; */ + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x6c, 0x69, /* 0x00000500: font-variant-li */ + 0x67, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, /* 0x00000510: gatures: normal; */ + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x2d, 0x63, 0x61, /* 0x00000520: font-variant-ca */ + 0x70, 0x73, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x66, 0x6f, 0x6e, 0x74, /* 0x00000530: ps: normal; font */ + 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x30, 0x30, 0x3b, 0x20, 0x6c, 0x65, /* 0x00000540: -weight: 400; le */ + 0x74, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x6e, 0x6f, /* 0x00000550: tter-spacing: no */ + 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x20, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x73, 0x3a, 0x20, 0x32, /* 0x00000560: rmal; orphans: 2 */ + 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x73, 0x74, /* 0x00000570: ; text-align: st */ + 0x61, 0x72, 0x74, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x69, 0x6e, 0x64, 0x65, 0x6e, 0x74, /* 0x00000580: art; text-indent */ + 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, /* 0x00000590: : 0px; text-tran */ + 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x3b, 0x20, 0x77, 0x68, 0x69, /* 0x000005a0: sform: none; whi */ + 0x74, 0x65, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, /* 0x000005b0: te-space: normal */ + 0x3b, 0x20, 0x77, 0x69, 0x64, 0x6f, 0x77, 0x73, 0x3a, 0x20, 0x32, 0x3b, 0x20, 0x77, 0x6f, 0x72, /* 0x000005c0: ; widows: 2; wor */ + 0x64, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, /* 0x000005d0: d-spacing: 0px; */ + 0x2d, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2d, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x73, 0x74, 0x72, /* 0x000005e0: -webkit-text-str */ + 0x6f, 0x6b, 0x65, 0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x20, /* 0x000005f0: oke-width: 0px; */ + 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, /* 0x00000600: background-color */ + 0x3a, 0x20, 0x72, 0x67, 0x62, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, /* 0x00000610: : rgb(255, 255, */ + 0x32, 0x35, 0x35, 0x29, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, 0x6f, 0x72, /* 0x00000620: 255); text-decor */ + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, 0x73, 0x3a, /* 0x00000630: ation-thickness: */ + 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, /* 0x00000640: initial; text-d */ + 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, /* 0x00000650: ecoration-style: */ + 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, /* 0x00000660: initial; text-d */ + 0x65, 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, /* 0x00000670: ecoration-color: */ + 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x3b, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, /* 0x00000680: initial; displa */ + 0x79, 0x3a, 0x20, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x21, 0x69, 0x6d, 0x70, 0x6f, 0x72, /* 0x00000690: y: inline !impor */ + 0x74, 0x61, 0x6e, 0x74, 0x3b, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, /* 0x000006a0: tant; float: non */ + 0x65, 0x3b, 0x22, 0x3e, 0x22, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x6e, 0x74, /* 0x000006b0: e;">" for an int */ + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, /* 0x000006c0: roduction.<.span */ + 0x3e, 0x00 /* 0x000006d0: > */ +}; + +const unsigned g_cbVBoxOrgMimeHtml1 = sizeof(g_abVBoxOrgMimeHtml1); + +#endif /* !VBOX_INCLUDED_SRC_VBoxOrgMimeHtml1_h */ diff --git a/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgMimeHtml1.txt b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgMimeHtml1.txt new file mode 100644 index 00000000..6d5b4901 --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/VBoxOrgMimeHtml1.txt @@ -0,0 +1 @@ +<span style="color: rgb(0, 0, 0); font-family: Verdana, "Bitstream Vera Sans", sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">See "</span><a class="wiki" href="https://www.virtualbox.org/wiki/VirtualBox" style="text-decoration: none; color: rgb(0, 0, 192); border-bottom: none; font-family: Verdana, "Bitstream Vera Sans", sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);">About VirtualBox</a><span style="color: rgb(0, 0, 0); font-family: Verdana, "Bitstream Vera Sans", sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">" for an introduction.</span>
\ No newline at end of file diff --git a/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardMockHGCM.cpp b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardMockHGCM.cpp new file mode 100644 index 00000000..f61f5dbd --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardMockHGCM.cpp @@ -0,0 +1,735 @@ +/* $Id: tstClipboardMockHGCM.cpp $ */ +/** @file + * Shared Clipboard host service test case. + */ + +/* + * Copyright (C) 2011-2022 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 "../VBoxSharedClipboardSvc-internal.h" + +#include <VBox/HostServices/VBoxClipboardSvc.h> +#include <VBox/VBoxGuestLib.h> +#ifdef RT_OS_LINUX +# include <VBox/GuestHost/SharedClipboard-x11.h> +#endif +#ifdef RT_OS_WINDOWS +# include <VBox/GuestHost/SharedClipboard-win.h> +#endif + +#include <VBox/GuestHost/HGCMMock.h> +#include <VBox/GuestHost/HGCMMockUtils.h> + +#include <iprt/assert.h> +#include <iprt/initterm.h> +#include <iprt/mem.h> +#include <iprt/rand.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/test.h> +#include <iprt/utf16.h> + + +/********************************************************************************************************************************* +* Static globals * +*********************************************************************************************************************************/ +static RTTEST g_hTest; + + +/********************************************************************************************************************************* +* Shared Clipboard testing * +*********************************************************************************************************************************/ +struct CLIPBOARDTESTDESC; +/** Pointer to a test description. */ +typedef CLIPBOARDTESTDESC *PTESTDESC; + +struct CLIPBOARDTESTCTX; +/** Pointer to a test context. */ +typedef CLIPBOARDTESTCTX *PCLIPBOARDTESTCTX; + +/** Pointer a test descriptor. */ +typedef CLIPBOARDTESTDESC *PTESTDESC; + +typedef DECLCALLBACKTYPE(int, FNTESTSETUP,(PCLIPBOARDTESTCTX pTstCtx, void **ppvCtx)); +/** Pointer to a test setup callback. */ +typedef FNTESTSETUP *PFNTESTSETUP; + +typedef DECLCALLBACKTYPE(int, FNTESTEXEC,(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx)); +/** Pointer to a test exec callback. */ +typedef FNTESTEXEC *PFNTESTEXEC; + +typedef DECLCALLBACKTYPE(int, FNTESTDESTROY,(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx)); +/** Pointer to a test destroy callback. */ +typedef FNTESTDESTROY *PFNTESTDESTROY; + + +/** + * Structure for keeping a clipboard test task. + */ +typedef struct CLIPBOARDTESTTASK +{ + SHCLFORMATS enmFmtHst; + SHCLFORMATS enmFmtGst; + /** For testing chunked reads / writes. */ + size_t cbChunk; + /** Data buffer to read / write for this task. + * Can be NULL if not needed. */ + void *pvData; + /** Size (in bytes) of \a pvData. */ + size_t cbData; + /** Number of bytes read / written from / to \a pvData. */ + size_t cbProcessed; +} CLIPBOARDTESTTASK; +typedef CLIPBOARDTESTTASK *PCLIPBOARDTESTTASK; + +/** + * Structure for keeping a clipboard test context. + */ +typedef struct CLIPBOARDTESTCTX +{ + /** The HGCM Mock utils context. */ + TSTHGCMUTILSCTX HGCM; + /** Clipboard-specific task data. */ + CLIPBOARDTESTTASK Task; + struct + { + /** The VbglR3 Shared Clipboard context to work on. */ + VBGLR3SHCLCMDCTX CmdCtx; + } Guest; +} CLIPBOARDTESTCTX; + +/** The one and only clipboard test context. One at a time. */ +CLIPBOARDTESTCTX g_TstCtx; + +/** + * Structure for keeping a clipboard test description. + */ +typedef struct CLIPBOARDTESTDESC +{ + /** The setup callback. */ + PFNTESTSETUP pfnSetup; + /** The exec callback. */ + PFNTESTEXEC pfnExec; + /** The destruction callback. */ + PFNTESTDESTROY pfnDestroy; +} CLIPBOARDTESTDESC; + +typedef struct SHCLCONTEXT +{ +} SHCLCONTEXT; + + +static int tstSetModeRc(PTSTHGCMMOCKSVC pSvc, uint32_t uMode, int rcExpected) +{ + VBOXHGCMSVCPARM aParms[2]; + HGCMSvcSetU32(&aParms[0], uMode); + int rc2 = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, aParms); + RTTESTI_CHECK_MSG_RET(rcExpected == rc2, ("Expected %Rrc, got %Rrc\n", rcExpected, rc2), rc2); + if (RT_SUCCESS(rcExpected)) + { + uint32_t const uModeRet = ShClSvcGetMode(); + RTTESTI_CHECK_MSG_RET(uMode == uModeRet, ("Expected mode %RU32, got %RU32\n", uMode, uModeRet), VERR_WRONG_TYPE); + } + return rc2; +} + +static int tstClipboardSetMode(PTSTHGCMMOCKSVC pSvc, uint32_t uMode) +{ + return tstSetModeRc(pSvc, uMode, VINF_SUCCESS); +} + +static bool tstClipboardGetMode(PTSTHGCMMOCKSVC pSvc, uint32_t uModeExpected) +{ + RT_NOREF(pSvc); + RTTESTI_CHECK_RET(ShClSvcGetMode() == uModeExpected, false); + return true; +} + +static void tstOperationModes(void) +{ + struct VBOXHGCMSVCPARM parms[2]; + uint32_t u32Mode; + int rc; + + RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_MODE"); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + /* Reset global variable which doesn't reset itself. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_OFF); + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + u32Mode = ShClSvcGetMode(); + RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_OFF, ("u32Mode=%u\n", (unsigned) u32Mode)); + + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 0, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 2, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + HGCMSvcSetU64(&parms[0], 99); + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + tstClipboardSetMode(pSvc, VBOX_SHCL_MODE_HOST_TO_GUEST); + tstSetModeRc(pSvc, 99, VERR_NOT_SUPPORTED); + tstClipboardGetMode(pSvc, VBOX_SHCL_MODE_OFF); +} + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +static void testSetTransferMode(void) +{ + RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE"); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + /* Invalid parameter. */ + VBOXHGCMSVCPARM parms[2]; + HGCMSvcSetU64(&parms[0], 99); + int rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + /* Invalid mode. */ + HGCMSvcSetU32(&parms[0], 99); + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_FLAGS); + + /* Enable transfers. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_ENABLED); + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); + + /* Disable transfers again. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_DISABLED); + rc = TstHgcmMockSvcHostCall(pSvc, NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); +} +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +static void testGuestSimple(void) +{ + RTTestISub("Testing client (guest) API - Simple"); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + /* Preparations. */ + VBGLR3SHCLCMDCTX Ctx; + RT_ZERO(Ctx); + + /* + * Multiple connects / disconnects. + */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardConnectEx(&Ctx, VBOX_SHCL_GF_0_CONTEXT_ID)); + RTTESTI_CHECK_RC_OK(VbglR3ClipboardDisconnectEx(&Ctx)); + /* Report bogus guest features while connecting. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardConnectEx(&Ctx, 0xdeadbeef)); + RTTESTI_CHECK_RC_OK(VbglR3ClipboardDisconnectEx(&Ctx)); + + RTTESTI_CHECK_RC_OK(VbglR3ClipboardConnectEx(&Ctx, VBOX_SHCL_GF_0_CONTEXT_ID)); + + /* + * Feature tests. + */ + + RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFeatures(Ctx.idClient, 0x0, NULL /* pfHostFeatures */)); + /* Report bogus features to the host. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFeatures(Ctx.idClient, 0xdeadb33f, NULL /* pfHostFeatures */)); + + /* + * Access denied tests. + */ + + /* Try reading data from host. */ + uint8_t abData[32]; uint32_t cbIgnored; + RTTESTI_CHECK_RC(VbglR3ClipboardReadData(Ctx.idClient, VBOX_SHCL_FMT_UNICODETEXT, + abData, sizeof(abData), &cbIgnored), VERR_ACCESS_DENIED); + /* Try writing data without reporting formats before (legacy). */ + RTTESTI_CHECK_RC(VbglR3ClipboardWriteData(Ctx.idClient, 0xdeadb33f, abData, sizeof(abData)), VERR_ACCESS_DENIED); + /* Try writing data without reporting formats before. */ + RTTESTI_CHECK_RC(VbglR3ClipboardWriteDataEx(&Ctx, 0xdeadb33f, abData, sizeof(abData)), VERR_ACCESS_DENIED); + /* Report bogus formats to the host. */ + RTTESTI_CHECK_RC(VbglR3ClipboardReportFormats(Ctx.idClient, 0xdeadb33f), VERR_ACCESS_DENIED); + /* Report supported formats to host. */ + RTTESTI_CHECK_RC(VbglR3ClipboardReportFormats(Ctx.idClient, + VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_BITMAP | VBOX_SHCL_FMT_HTML), + VERR_ACCESS_DENIED); + /* + * Access allowed tests. + */ + tstClipboardSetMode(pSvc, VBOX_SHCL_MODE_BIDIRECTIONAL); + + /* Try writing data without reporting formats before. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardWriteDataEx(&Ctx, 0xdeadb33f, abData, sizeof(abData))); + /* Try reading data from host. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardReadData(Ctx.idClient, VBOX_SHCL_FMT_UNICODETEXT, + abData, sizeof(abData), &cbIgnored)); + /* Report bogus formats to the host. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFormats(Ctx.idClient, 0xdeadb33f)); + /* Report supported formats to host. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardReportFormats(Ctx.idClient, + VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_BITMAP | VBOX_SHCL_FMT_HTML)); + /* Tear down. */ + RTTESTI_CHECK_RC_OK(VbglR3ClipboardDisconnectEx(&Ctx)); +} + +static RTUTF16 tstGetRandUtf8(void) +{ + return RTRandU32Ex(0x20, 0x7A); +} + +static char *tstGenerateUtf8StringA(uint32_t uCch) +{ + char * pszRand = (char *)RTMemAlloc(uCch + 1); + for (uint32_t i = 0; i < uCch; i++) + pszRand[i] = tstGetRandUtf8(); + pszRand[uCch] = 0; + return pszRand; +} + +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) +static RTUTF16 tstGetRandUtf16(void) +{ + RTUTF16 wc; + do + { + wc = (RTUTF16)RTRandU32Ex(1, 0xfffd); + } while (wc >= 0xd800 && wc <= 0xdfff); + return wc; +} + +static PRTUTF16 tstGenerateUtf16StringA(uint32_t uCch) +{ + PRTUTF16 pwszRand = (PRTUTF16)RTMemAlloc((uCch + 1) * sizeof(RTUTF16)); + for (uint32_t i = 0; i < uCch; i++) + pwszRand[i] = tstGetRandUtf16(); + pwszRand[uCch] = 0; + return pwszRand; +} +#endif /* RT_OS_WINDOWS) || RT_OS_OS2 */ + +static void testSetHeadless(void) +{ + RTTestISub("Testing HOST_FN_SET_HEADLESS"); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + VBOXHGCMSVCPARM parms[2]; + HGCMSvcSetU32(&parms[0], false); + int rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + bool fHeadless = ShClSvcGetHeadless(); + RTTESTI_CHECK_MSG(fHeadless == false, ("fHeadless=%RTbool\n", fHeadless)); + rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 0, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 2, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + HGCMSvcSetU64(&parms[0], 99); + rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + HGCMSvcSetU32(&parms[0], true); + rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + fHeadless = ShClSvcGetHeadless(); + RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless)); + HGCMSvcSetU32(&parms[0], 99); + rc = pSvc->fnTable.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + fHeadless = ShClSvcGetHeadless(); + RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless)); +} + +static void testHostCall(void) +{ + tstOperationModes(); +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + testSetTransferMode(); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + testSetHeadless(); +} + + +/********************************************************************************************************************************* + * Test: Guest reading from host * + ********************************************************************************************************************************/ +#if defined (RT_OS_LINUX) || defined (RT_OS_SOLARIS) +/* Called from SHCLX11 thread. */ +static DECLCALLBACK(int) tstTestReadFromHost_ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser) +{ + RT_NOREF(pCtx, fFormats, pvUser); + + RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "tstTestReadFromHost_SvcReportFormatsCallback: fFormats=%#x\n", fFormats); + return VINF_SUCCESS; +} + +/* Called by the backend, e.g. for X11 in the SHCLX11 thread. */ +static DECLCALLBACK(int) tstTestReadFromHost_OnClipboardReadCallback(PSHCLCONTEXT pCtx, + SHCLFORMAT uFmt, void **ppv, size_t *pcb, void *pvUser) +{ + RT_NOREF(pCtx, uFmt, pvUser); + + PCLIPBOARDTESTTASK pTask = (PCLIPBOARDTESTTASK)TstHGCMUtilsTaskGetCurrent(&g_TstCtx.HGCM)->pvUser; + + void *pvData = NULL; + size_t cbData = pTask->cbData - pTask->cbProcessed; + if (cbData) + { + pvData = RTMemDup((uint8_t *)pTask->pvData + pTask->cbProcessed, cbData); + AssertPtr(pvData); + } + + RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Host reporting back %RU32 bytes of data\n", cbData); + + *ppv = pvData; + *pcb = cbData; + + return VINF_SUCCESS; +} +#endif /* (RT_OS_LINUX) || defined (RT_OS_SOLARIS) */ + +typedef struct TSTUSERMOCK +{ +#if defined(RT_OS_LINUX) + SHCLX11CTX X11Ctx; +#endif + PSHCLCONTEXT pCtx; +} TSTUSERMOCK; +typedef TSTUSERMOCK *PTSTUSERMOCK; + +static void tstTestReadFromHost_MockInit(PTSTUSERMOCK pUsrMock, const char *pszName) +{ +#if defined(RT_OS_LINUX) + SHCLCALLBACKS Callbacks; + RT_ZERO(Callbacks); + Callbacks.pfnReportFormats = tstTestReadFromHost_ReportFormatsCallback; + Callbacks.pfnOnClipboardRead = tstTestReadFromHost_OnClipboardReadCallback; + + pUsrMock->pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT)); + AssertPtrReturnVoid(pUsrMock->pCtx); + + ShClX11Init(&pUsrMock->X11Ctx, &Callbacks, pUsrMock->pCtx, false); + ShClX11ThreadStartEx(&pUsrMock->X11Ctx, pszName, false /* fGrab */); + /* Give the clipboard time to synchronise. */ + RTThreadSleep(500); +#else + RT_NOREF(pUsrMock, pszName); +#endif /* RT_OS_LINUX */ +} + +static void tstTestReadFromHost_MockDestroy(PTSTUSERMOCK pUsrMock) +{ +#if defined(RT_OS_LINUX) + ShClX11ThreadStop(&pUsrMock->X11Ctx); + ShClX11Destroy(&pUsrMock->X11Ctx); + RTMemFree(pUsrMock->pCtx); +#else + RT_NOREF(pUsrMock); +#endif +} + +static int tstTestReadFromHost_DoIt(PCLIPBOARDTESTCTX pCtx, PCLIPBOARDTESTTASK pTask) +{ + size_t cbDst = RT_MAX(_64K, pTask->cbData); + uint8_t *pabDst = (uint8_t *)RTMemAllocZ(cbDst); + AssertPtrReturn(pabDst, VERR_NO_MEMORY); + + AssertPtr(pTask->pvData); /* Racing condition with host thread? */ + Assert(pTask->cbChunk); /* Buggy test? */ + Assert(pTask->cbChunk <= pTask->cbData); /* Ditto. */ + + size_t cbToRead = pTask->cbData; + switch (pTask->enmFmtGst) + { + case VBOX_SHCL_FMT_UNICODETEXT: +#ifndef RT_OS_WINDOWS /** @todo Not sure about OS/2. */ + cbToRead *= sizeof(RTUTF16); +#endif + break; + + default: + break; + } + + PVBGLR3SHCLCMDCTX pCmdCtx = &pCtx->Guest.CmdCtx; + + /* Do random chunked reads. */ + uint32_t const cChunkedReads = RTRandU32Ex(1, 16); + RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "%RU32 chunked reads\n", cChunkedReads); + for (uint32_t i = 0; i < cChunkedReads; i++) + { + /* Note! VbglR3ClipboardReadData() currently does not support chunked reads! + * It in turn returns VINF_BUFFER_OVERFLOW when the supplied buffer was too small. */ + + uint32_t cbChunk = RTRandU32Ex(1, (uint32_t)(pTask->cbData / cChunkedReads)); + uint32_t cbRead = 0; + RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Guest trying to read %RU32 bytes\n", cbChunk); + int vrc2 = VbglR3ClipboardReadData(pCmdCtx->idClient, pTask->enmFmtGst, pabDst, cbChunk, &cbRead); + if ( vrc2 == VINF_SUCCESS + && cbRead == 0) /* No data there yet? */ + { + RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "No data (yet) from host\n"); + RTThreadSleep(10); + continue; + } + RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Trying reading host clipboard data with a %RU32 buffer -> %Rrc (%RU32)\n", cbChunk, vrc2, cbRead); + RTTEST_CHECK_MSG(g_hTest, vrc2 == VINF_BUFFER_OVERFLOW, (g_hTest, "Got %Rrc, expected VINF_BUFFER_OVERFLOW\n", vrc2)); + } + + /* Last read: Read the data with a buffer big enough. This must succeed. */ + RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Reading full data (%zu)\n", pTask->cbData); + uint32_t cbRead = 0; + int vrc2 = VbglR3ClipboardReadData(pCmdCtx->idClient, pTask->enmFmtGst, pabDst, (uint32_t)cbDst, &cbRead); + RTTEST_CHECK_MSG(g_hTest, vrc2 == VINF_SUCCESS, (g_hTest, "Got %Rrc, expected VINF_SUCCESS\n", vrc2)); + RTTEST_CHECK_MSG(g_hTest, cbRead == cbToRead, (g_hTest, "Read %RU32 bytes, expected %zu\n", cbRead, cbToRead)); + + if (pTask->enmFmtGst == VBOX_SHCL_FMT_UNICODETEXT) + RTTEST_CHECK_MSG(g_hTest, RTUtf16ValidateEncoding((PRTUTF16)pabDst) == VINF_SUCCESS, (g_hTest, "Read data is not valid UTF-16\n")); + if (cbRead == cbToRead) + { +#ifndef RT_OS_WINDOWS /** @todo Not sure about OS/2. */ + PRTUTF16 pwszSrc = NULL; + RTTEST_CHECK(g_hTest, RT_SUCCESS(RTStrToUtf16((const char *)pTask->pvData, &pwszSrc))); + RTTEST_CHECK_MSG(g_hTest, memcmp(pwszSrc, pabDst, cbRead) == 0, (g_hTest, "Read data does not match host data\n")); + RTUtf16Free(pwszSrc); +#else + RTTEST_CHECK_MSG(g_hTest, memcmp(pTask->pvData, pabDst, cbRead) == 0, (g_hTest, "Read data does not match host data\n")); +#endif + } + + RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Read data from host:\n%.*Rhxd\n", cbRead, pabDst); + + RTMemFree(pabDst); + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) tstTestReadFromHost_ThreadGuest(PTSTHGCMUTILSCTX pCtx, void *pvCtx) +{ + RTThreadSleep(1000); /* Fudge; wait until the host has prepared the data for the clipboard. */ + + PCLIPBOARDTESTCTX pTstCtx = (PCLIPBOARDTESTCTX)pvCtx; + AssertPtr(pTstCtx); + + RT_ZERO(pTstCtx->Guest.CmdCtx); + RTTEST_CHECK_RC_OK(g_hTest, VbglR3ClipboardConnectEx(&pTstCtx->Guest.CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID)); + + RTThreadSleep(1000); /* Fudge; wait until the host has prepared the data for the clipboard. */ + + PCLIPBOARDTESTTASK pTstTask = (PCLIPBOARDTESTTASK)pCtx->Task.pvUser; + AssertPtr(pTstTask); + tstTestReadFromHost_DoIt(pTstCtx, pTstTask); + + /* Signal that the task ended. */ + TstHGCMUtilsTaskSignal(&pCtx->Task, VINF_SUCCESS); + + RTTEST_CHECK_RC_OK(g_hTest, VbglR3ClipboardDisconnectEx(&pTstCtx->Guest.CmdCtx)); + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) tstTestReadFromHost_ClientConnectedCallback(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient, + void *pvUser) +{ + RT_NOREF(pCtx, pClient); + + PCLIPBOARDTESTCTX pTstCtx = (PCLIPBOARDTESTCTX)pvUser; + AssertPtr(pTstCtx); RT_NOREF(pTstCtx); + + RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Client %RU32 connected\n", pClient->idClient); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) tstTestReadFromHostSetup(PCLIPBOARDTESTCTX pTstCtx, void **ppvCtx) +{ + RT_NOREF(ppvCtx); + + /* Set the right clipboard mode, so that the guest can read from the host. */ + tstClipboardSetMode(TstHgcmMockSvcInst(), VBOX_SHCL_MODE_BIDIRECTIONAL); + + /* Start the host thread first, so that the guest thread can connect to it later. */ + TSTHGCMUTILSHOSTCALLBACKS HostCallbacks; + RT_ZERO(HostCallbacks); + HostCallbacks.pfnOnClientConnected = tstTestReadFromHost_ClientConnectedCallback; + TstHGCMUtilsHostThreadStart(&pTstCtx->HGCM, &HostCallbacks, pTstCtx /* pvUser */); + + PCLIPBOARDTESTTASK pTask = &pTstCtx->Task; + AssertPtr(pTask); + pTask->enmFmtGst = VBOX_SHCL_FMT_UNICODETEXT; + pTask->enmFmtHst = pTask->enmFmtGst; + pTask->cbChunk = RTRandU32Ex(1, 512); + pTask->cbData = RT_ALIGN_32(pTask->cbChunk * RTRandU32Ex(1, 16), 2); + Assert(pTask->cbData % sizeof(RTUTF16) == 0); +#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2) + pTask->pvData = tstGenerateUtf8StringA(pTask->cbData); + pTask->cbData++; /* Add terminating zero. */ +#else + pTask->pvData = tstGenerateUtf16StringA((uint32_t)(pTask->cbData /* We use bytes == chars here */)); + pTask->cbData *= sizeof(RTUTF16); + pTask->cbData += sizeof(RTUTF16); /* Add terminating zero. */ +#endif + pTask->cbProcessed = 0; + + int rc = VINF_SUCCESS; + +#if defined (RT_OS_LINUX) || defined (RT_OS_SOLARIS) + /* Initialize the Shared Clipboard backend callbacks. */ + PSHCLBACKEND pBackend = ShClSvcGetBackend(); + + SHCLCALLBACKS ShClCallbacks; + RT_ZERO(ShClCallbacks); + ShClCallbacks.pfnReportFormats = tstTestReadFromHost_ReportFormatsCallback; + ShClCallbacks.pfnOnClipboardRead = tstTestReadFromHost_OnClipboardReadCallback; + ShClBackendSetCallbacks(pBackend, &ShClCallbacks); +#elif defined (RT_OS_WINDOWS) + rc = SharedClipboardWinOpen(GetDesktopWindow()); + if (RT_SUCCESS(rc)) + { + rc = SharedClipboardWinDataWrite(CF_UNICODETEXT, pTask->pvData, (uint32_t)pTask->cbData); + SharedClipboardWinClose(); + } +#endif /* defined (RT_OS_LINUX) || defined (RT_OS_SOLARIS) */ + + RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Host data (%RU32):\n%.*Rhxd\n", pTask->cbData, pTask->cbData, pTask->pvData); + return rc; +} + +static DECLCALLBACK(int) tstTestReadFromHostExec(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx) +{ + RT_NOREF(pvCtx); + + TstHGCMUtilsGuestThreadStart(&pTstCtx->HGCM, tstTestReadFromHost_ThreadGuest, pTstCtx); + + PTSTHGCMUTILSTASK pTask = (PTSTHGCMUTILSTASK)TstHGCMUtilsTaskGetCurrent(&pTstCtx->HGCM); + + bool fUseMock = false; + TSTUSERMOCK UsrMock; + if (fUseMock) + tstTestReadFromHost_MockInit(&UsrMock, "tstX11Hst"); + + /* Wait until the task has been finished. */ + TstHGCMUtilsTaskWait(pTask, RT_MS_30SEC); + + if (fUseMock) + tstTestReadFromHost_MockDestroy(&UsrMock); + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) tstTestReadFromHostDestroy(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx) +{ + RT_NOREF(pvCtx); + + int vrc = TstHGCMUtilsGuestThreadStop(&pTstCtx->HGCM); + AssertRC(vrc); + vrc = TstHGCMUtilsHostThreadStop(&pTstCtx->HGCM); + AssertRC(vrc); + + return vrc; +} + + +/********************************************************************************************************************************* + * Main * + ********************************************************************************************************************************/ + +/** Test definition table. */ +CLIPBOARDTESTDESC g_aTests[] = +{ + /* Tests guest reading clipboard data from the host. */ + { tstTestReadFromHostSetup, tstTestReadFromHostExec, tstTestReadFromHostDestroy } +}; +/** Number of tests defined. */ +unsigned g_cTests = RT_ELEMENTS(g_aTests); + +static int tstOne(PTESTDESC pTstDesc) +{ + PCLIPBOARDTESTCTX pTstCtx = &g_TstCtx; + + void *pvCtx; + int rc = pTstDesc->pfnSetup(pTstCtx, &pvCtx); + if (RT_SUCCESS(rc)) + { + rc = pTstDesc->pfnExec(pTstCtx, pvCtx); + + int rc2 = pTstDesc->pfnDestroy(pTstCtx, pvCtx); + if (RT_SUCCESS(rc)) + rc = rc2; + } + + return rc; +} + +int main(int argc, char *argv[]) +{ + /* + * Init the runtime, test and say hello. + */ + const char *pcszExecName; + NOREF(argc); + pcszExecName = strrchr(argv[0], '/'); + pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0]; + RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(g_hTest); + +#ifndef DEBUG_andy + /* Don't let assertions in the host service panic (core dump) the test cases. */ + RTAssertSetMayPanic(false); +#endif + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + TstHgcmMockSvcCreate(pSvc, sizeof(SHCLCLIENT)); + TstHgcmMockSvcStart(pSvc); + + /* + * Run the tests. + */ + if (0) + { + testGuestSimple(); + testHostCall(); + } + + RT_ZERO(g_TstCtx); + + PTSTHGCMUTILSCTX pCtx = &g_TstCtx.HGCM; + TstHGCMUtilsCtxInit(pCtx, pSvc); + + PTSTHGCMUTILSTASK pTask = (PTSTHGCMUTILSTASK)TstHGCMUtilsTaskGetCurrent(pCtx); + TstHGCMUtilsTaskInit(pTask); + pTask->pvUser = &g_TstCtx.Task; + + for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++) + tstOne(&g_aTests[i]); + + TstHGCMUtilsTaskDestroy(pTask); + + TstHgcmMockSvcStop(pSvc); + TstHgcmMockSvcDestroy(pSvc); + + /* + * Summary + */ + return RTTestSummaryAndDestroy(g_hTest); +} + diff --git a/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp new file mode 100644 index 00000000..7a27693a --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp @@ -0,0 +1,336 @@ +/* $Id: tstClipboardServiceHost.cpp $ */ +/** @file + * Shared Clipboard host service test case. + */ + +/* + * Copyright (C) 2011-2022 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 "../VBoxSharedClipboardSvc-internal.h" + +#include <VBox/HostServices/VBoxClipboardSvc.h> + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/test.h> + +extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable); + +static SHCLCLIENT g_Client; +static VBOXHGCMSVCHELPERS g_Helpers = { NULL }; + +/** Simple call handle structure for the guest call completion callback */ +struct VBOXHGCMCALLHANDLE_TYPEDEF +{ + /** Where to store the result code */ + int32_t rc; +}; + +/** Call completion callback for guest calls. */ +static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) +{ + callHandle->rc = rc; + return VINF_SUCCESS; +} + +static int setupTable(VBOXHGCMSVCFNTABLE *pTable) +{ + pTable->cbSize = sizeof(*pTable); + pTable->u32Version = VBOX_HGCM_SVC_VERSION; + g_Helpers.pfnCallComplete = callComplete; + pTable->pHelpers = &g_Helpers; + return VBoxHGCMSvcLoad(pTable); +} + +static void testSetMode(void) +{ + struct VBOXHGCMSVCPARM parms[2]; + VBOXHGCMSVCFNTABLE table; + uint32_t u32Mode; + int rc; + + RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_MODE"); + rc = setupTable(&table); + RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc)); + + /* Reset global variable which doesn't reset itself. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_OFF); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + u32Mode = ShClSvcGetMode(); + RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_OFF, ("u32Mode=%u\n", (unsigned) u32Mode)); + + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 0, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 2, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + HGCMSvcSetU64(&parms[0], 99); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_HOST_TO_GUEST); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + u32Mode = ShClSvcGetMode(); + RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_HOST_TO_GUEST, ("u32Mode=%u\n", (unsigned) u32Mode)); + + HGCMSvcSetU32(&parms[0], 99); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_NOT_SUPPORTED); + + u32Mode = ShClSvcGetMode(); + RTTESTI_CHECK_MSG(u32Mode == VBOX_SHCL_MODE_OFF, ("u32Mode=%u\n", (unsigned) u32Mode)); + table.pfnUnload(NULL); +} + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +static void testSetTransferMode(void) +{ + struct VBOXHGCMSVCPARM parms[2]; + VBOXHGCMSVCFNTABLE table; + + RTTestISub("Testing VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE"); + int rc = setupTable(&table); + RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc)); + + /* Invalid parameter. */ + HGCMSvcSetU64(&parms[0], 99); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + + /* Invalid mode. */ + HGCMSvcSetU32(&parms[0], 99); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_FLAGS); + + /* Enable transfers. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_ENABLED); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); + + /* Disable transfers again. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_TRANSFER_MODE_DISABLED); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1, parms); + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); +} +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/* Adds a host data read request message to the client's message queue. */ +static void testMsgAddReadData(PSHCLCLIENT pClient, SHCLFORMATS fFormats) +{ + int rc = ShClSvcGuestDataRequest(pClient, fFormats, NULL /* pidEvent */); + RTTESTI_CHECK_RC_OK(rc); +} + +/* Does testing of VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, needed for providing compatibility to older Guest Additions clients. */ +static void testGetHostMsgOld(void) +{ + struct VBOXHGCMSVCPARM parms[2]; + VBOXHGCMSVCFNTABLE table; + VBOXHGCMCALLHANDLE_TYPEDEF call; + int rc; + + RTTestISub("Setting up VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT test"); + rc = setupTable(&table); + RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc)); + /* Unless we are bidirectional the host message requests will be dropped. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_BIDIRECTIONAL); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + + + RTTestISub("Testing one format, waiting guest call."); + RT_ZERO(g_Client); + HGCMSvcSetU32(&parms[0], 0); + HGCMSvcSetU32(&parms[1], 0); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0); + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This should get updated only when the guest call completes. */ + testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_UNICODETEXT); + RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA); + RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_UNICODETEXT); + RTTESTI_CHECK_RC_OK(call.rc); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */ + table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client); + + RTTestISub("Testing one format, no waiting guest calls."); + RT_ZERO(g_Client); + table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0); + testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_HTML); + HGCMSvcSetU32(&parms[0], 0); + HGCMSvcSetU32(&parms[1], 0); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA); + RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_HTML); + RTTESTI_CHECK_RC_OK(call.rc); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */ + table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client); + + RTTestISub("Testing two formats, waiting guest call."); + RT_ZERO(g_Client); + table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0); + HGCMSvcSetU32(&parms[0], 0); + HGCMSvcSetU32(&parms[1], 0); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This should get updated only when the guest call completes. */ + testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_HTML); + RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA); + RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_UNICODETEXT); + RTTESTI_CHECK_RC_OK(call.rc); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA); + RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_HTML); + RTTESTI_CHECK_RC_OK(call.rc); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */ + table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client); + + RTTestISub("Testing two formats, no waiting guest calls."); + RT_ZERO(g_Client); + table.pfnConnect(NULL, 1 /* clientId */, &g_Client, 0, 0); + testMsgAddReadData(&g_Client, VBOX_SHCL_FMT_UNICODETEXT | VBOX_SHCL_FMT_HTML); + HGCMSvcSetU32(&parms[0], 0); + HGCMSvcSetU32(&parms[1], 0); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA); + RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_UNICODETEXT); + RTTESTI_CHECK_RC_OK(call.rc); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK(parms[0].u.uint32 == VBOX_SHCL_HOST_MSG_READ_DATA); + RTTESTI_CHECK(parms[1].u.uint32 == VBOX_SHCL_FMT_HTML); + RTTESTI_CHECK_RC_OK(call.rc); + call.rc = VERR_IPE_UNINITIALIZED_STATUS; + table.pfnCall(NULL, &call, 1 /* clientId */, &g_Client, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, 2, parms, 0); + RTTESTI_CHECK_RC(call.rc, VERR_IPE_UNINITIALIZED_STATUS); /* This call should not complete yet. */ + table.pfnDisconnect(NULL, 1 /* clientId */, &g_Client); + table.pfnUnload(NULL); +} + +static void testSetHeadless(void) +{ + struct VBOXHGCMSVCPARM parms[2]; + VBOXHGCMSVCFNTABLE table; + bool fHeadless; + int rc; + + RTTestISub("Testing HOST_FN_SET_HEADLESS"); + rc = setupTable(&table); + RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc)); + /* Reset global variable which doesn't reset itself. */ + HGCMSvcSetU32(&parms[0], false); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, + 1, parms); + RTTESTI_CHECK_RC_OK(rc); + fHeadless = ShClSvcGetHeadless(); + RTTESTI_CHECK_MSG(fHeadless == false, ("fHeadless=%RTbool\n", fHeadless)); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, + 0, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, + 2, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + HGCMSvcSetU64(&parms[0], 99); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, + 1, parms); + RTTESTI_CHECK_RC(rc, VERR_INVALID_PARAMETER); + HGCMSvcSetU32(&parms[0], true); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, + 1, parms); + RTTESTI_CHECK_RC_OK(rc); + fHeadless = ShClSvcGetHeadless(); + RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless)); + HGCMSvcSetU32(&parms[0], 99); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_HEADLESS, + 1, parms); + RTTESTI_CHECK_RC_OK(rc); + fHeadless = ShClSvcGetHeadless(); + RTTESTI_CHECK_MSG(fHeadless == true, ("fHeadless=%RTbool\n", fHeadless)); + table.pfnUnload(NULL); +} + +static void testHostCall(void) +{ + testSetMode(); +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + testSetTransferMode(); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + testSetHeadless(); +} + +int main(int argc, char *argv[]) +{ + /* + * Init the runtime, test and say hello. + */ + const char *pcszExecName; + NOREF(argc); + pcszExecName = strrchr(argv[0], '/'); + pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0]; + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + /* Don't let assertions in the host service panic (core dump) the test cases. */ + RTAssertSetMayPanic(false); + + /* + * Run the tests. + */ + testHostCall(); + testGetHostMsgOld(); + + /* + * Summary + */ + return RTTestSummaryAndDestroy(hTest); +} + +int ShClBackendInit(PSHCLBACKEND, VBOXHGCMSVCFNTABLE *) { return VINF_SUCCESS; } +void ShClBackendDestroy(PSHCLBACKEND) { } +int ShClBackendDisconnect(PSHCLBACKEND, PSHCLCLIENT) { return VINF_SUCCESS; } +int ShClBackendConnect(PSHCLBACKEND, PSHCLCLIENT, bool) { return VINF_SUCCESS; } +int ShClBackendReportFormats(PSHCLBACKEND, PSHCLCLIENT, SHCLFORMATS) { AssertFailed(); return VINF_SUCCESS; } +int ShClBackendReadData(PSHCLBACKEND, PSHCLCLIENT, PSHCLCLIENTCMDCTX, SHCLFORMAT, void *, uint32_t, unsigned int *) { AssertFailed(); return VERR_WRONG_ORDER; } +int ShClBackendWriteData(PSHCLBACKEND, PSHCLCLIENT, PSHCLCLIENTCMDCTX, SHCLFORMAT, void *, uint32_t) { AssertFailed(); return VINF_SUCCESS; } +int ShClBackendSync(PSHCLBACKEND, PSHCLCLIENT) { return VINF_SUCCESS; } + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int ShClBackendTransferCreate(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; } +int ShClBackendTransferDestroy(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; } +int ShClBackendTransferGetRoots(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; } +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + diff --git a/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceImpl.cpp b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceImpl.cpp new file mode 100644 index 00000000..07487a9f --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceImpl.cpp @@ -0,0 +1,205 @@ +/* $Id: tstClipboardServiceImpl.cpp $ */ +/** @file + * Shared Clipboard host service implementation (backend) test case. + */ + +/* + * Copyright (C) 2020-2022 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 "../VBoxSharedClipboardSvc-internal.h" + +#include <VBox/HostServices/VBoxClipboardSvc.h> +#ifdef RT_OS_WINDOWS +# include <VBox/GuestHost/SharedClipboard-win.h> +#endif + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/test.h> + +extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable); + +static SHCLCLIENT g_Client; +static VBOXHGCMSVCHELPERS g_Helpers = { NULL }; + +/** Simple call handle structure for the guest call completion callback */ +struct VBOXHGCMCALLHANDLE_TYPEDEF +{ + /** Where to store the result code */ + int32_t rc; +}; + +/** Call completion callback for guest calls. */ +static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) +{ + callHandle->rc = rc; + return VINF_SUCCESS; +} + +static int setupTable(VBOXHGCMSVCFNTABLE *pTable) +{ + pTable->cbSize = sizeof(*pTable); + pTable->u32Version = VBOX_HGCM_SVC_VERSION; + g_Helpers.pfnCallComplete = callComplete; + pTable->pHelpers = &g_Helpers; + return VBoxHGCMSvcLoad(pTable); +} + +int ShClBackendInit(PSHCLBACKEND, VBOXHGCMSVCFNTABLE *) { return VINF_SUCCESS; } +void ShClBackendDestroy(PSHCLBACKEND) { } +int ShClBackendDisconnect(PSHCLBACKEND, PSHCLCLIENT) { return VINF_SUCCESS; } +int ShClBackendConnect(PSHCLBACKEND, PSHCLCLIENT, bool) { return VINF_SUCCESS; } +int ShClBackendReportFormats(PSHCLBACKEND, PSHCLCLIENT, SHCLFORMATS) { AssertFailed(); return VINF_SUCCESS; } +int ShClBackendReadData(PSHCLBACKEND, PSHCLCLIENT, PSHCLCLIENTCMDCTX, SHCLFORMAT, void *, uint32_t, unsigned int *) { AssertFailed(); return VERR_WRONG_ORDER; } +int ShClBackendWriteData(PSHCLBACKEND, PSHCLCLIENT, PSHCLCLIENTCMDCTX, SHCLFORMAT, void *, uint32_t) { AssertFailed(); return VINF_SUCCESS; } +int ShClBackendSync(PSHCLBACKEND, PSHCLCLIENT) { return VINF_SUCCESS; } + +static void testAnnounceAndReadData(void) +{ + struct VBOXHGCMSVCPARM parms[2]; + VBOXHGCMSVCFNTABLE table; + int rc; + + RTTestISub("Setting up client ..."); + RTTestIDisableAssertions(); + + rc = setupTable(&table); + RTTESTI_CHECK_MSG_RETV(RT_SUCCESS(rc), ("rc=%Rrc\n", rc)); + /* Unless we are bidirectional the host message requests will be dropped. */ + HGCMSvcSetU32(&parms[0], VBOX_SHCL_MODE_BIDIRECTIONAL); + rc = table.pfnHostCall(NULL, VBOX_SHCL_HOST_FN_SET_MODE, 1, parms); + RTTESTI_CHECK_RC_OK(rc); + rc = shClSvcClientInit(&g_Client, 1 /* clientId */); + RTTESTI_CHECK_RC_OK(rc); + + RTTestIRestoreAssertions(); +} + +#ifdef RT_OS_WINDOWS +# include "VBoxOrgCfHtml1.h" /* From chrome 97.0.4692.71 */ +# include "VBoxOrgMimeHtml1.h" + +static void testHtmlCf(void) +{ + RTTestISub("CF_HTML"); + + char *pszOutput = NULL; + uint32_t cbOutput = UINT32_MAX/2; + RTTestIDisableAssertions(); + RTTESTI_CHECK_RC(SharedClipboardWinConvertCFHTMLToMIME("", 0, &pszOutput, &cbOutput), VERR_INVALID_PARAMETER); + RTTestIRestoreAssertions(); + + pszOutput = NULL; + cbOutput = UINT32_MAX/2; + RTTESTI_CHECK_RC(SharedClipboardWinConvertCFHTMLToMIME((char *)&g_abVBoxOrgCfHtml1[0], g_cbVBoxOrgCfHtml1, + &pszOutput, &cbOutput), VINF_SUCCESS); + RTTESTI_CHECK(cbOutput == g_cbVBoxOrgMimeHtml1); + RTTESTI_CHECK(memcmp(pszOutput, g_abVBoxOrgMimeHtml1, cbOutput) == 0); + RTMemFree(pszOutput); + + + static RTSTRTUPLE const s_aRoundTrips[] = + { + { RT_STR_TUPLE("") }, + { RT_STR_TUPLE("1") }, + { RT_STR_TUPLE("12") }, + { RT_STR_TUPLE("123") }, + { RT_STR_TUPLE("1234") }, + { RT_STR_TUPLE("12345") }, + { RT_STR_TUPLE("123456") }, + { RT_STR_TUPLE("1234567") }, + { RT_STR_TUPLE("12345678") }, + { RT_STR_TUPLE("123456789") }, + { RT_STR_TUPLE("1234567890") }, + { RT_STR_TUPLE("<h2>asdfkjhasdflhj</h2>") }, + { RT_STR_TUPLE("<h2>asdfkjhasdflhj</h2>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") }, + { (const char *)g_abVBoxOrgMimeHtml1, sizeof(g_abVBoxOrgMimeHtml1) }, + }; + + for (size_t i = 0; i < RT_ELEMENTS(s_aRoundTrips); i++) + { + int rc; + char *pszCfHtml = NULL; + uint32_t cbCfHtml = UINT32_MAX/2; + rc = SharedClipboardWinConvertMIMEToCFHTML(s_aRoundTrips[i].psz, s_aRoundTrips[i].cch + 1, &pszCfHtml, &cbCfHtml); + if (rc == VINF_SUCCESS) + { + if (strlen(pszCfHtml) + 1 != cbCfHtml) + RTTestIFailed("#%u: SharedClipboardWinConvertMIMEToCFHTML(%s, %#zx,,) returned incorrect length: %#x, actual %#zx", + i, s_aRoundTrips[i].psz, s_aRoundTrips[i].cch, cbCfHtml, strlen(pszCfHtml) + 1); + + char *pszHtml = NULL; + uint32_t cbHtml = UINT32_MAX/4; + rc = SharedClipboardWinConvertCFHTMLToMIME(pszCfHtml, (uint32_t)strlen(pszCfHtml), &pszHtml, &cbHtml); + if (rc == VINF_SUCCESS) + { + if (strlen(pszHtml) + 1 != cbHtml) + RTTestIFailed("#%u: SharedClipboardWinConvertCFHTMLToMIME(%s, %#zx,,) returned incorrect length: %#x, actual %#zx", + i, pszHtml, strlen(pszHtml), cbHtml, strlen(pszHtml) + 1); + if (strcmp(pszHtml, s_aRoundTrips[i].psz) != 0) + RTTestIFailed("#%u: roundtrip for '%s' LB %#zx failed, ended up with '%s'", + i, s_aRoundTrips[i].psz, s_aRoundTrips[i].cch, pszHtml); + RTMemFree(pszHtml); + } + else + RTTestIFailed("#%u: SharedClipboardWinConvertCFHTMLToMIME(%s, %#zx,,) returned %Rrc, expected VINF_SUCCESS", + i, pszCfHtml, strlen(pszCfHtml), rc); + RTMemFree(pszCfHtml); + } + else + RTTestIFailed("#%u: SharedClipboardWinConvertMIMEToCFHTML(%s, %#zx,,) returned %Rrc, expected VINF_SUCCESS", + i, s_aRoundTrips[i].psz, s_aRoundTrips[i].cch, rc); + } +} + +#endif /* RT_OS_WINDOWS */ + + +int main(int argc, char *argv[]) +{ + /* + * Init the runtime, test and say hello. + */ + const char *pcszExecName; + NOREF(argc); + pcszExecName = strrchr(argv[0], '/'); + pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0]; + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + /* + * Run the tests. + */ + testAnnounceAndReadData(); +#ifdef RT_OS_WINDOWS + testHtmlCf(); +#endif + + /* + * Summary + */ + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardTransfers.cpp b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardTransfers.cpp new file mode 100644 index 00000000..31bd2b90 --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardTransfers.cpp @@ -0,0 +1,389 @@ +/* $Id: tstClipboardTransfers.cpp $ */ +/** @file + * Shared Clipboard transfers test case. + */ + +/* + * Copyright (C) 2019-2022 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 "../VBoxSharedClipboardSvc-internal.h" + +#include <VBox/HostServices/VBoxClipboardSvc.h> + +#include <iprt/assert.h> +#include <iprt/dir.h> +#include <iprt/file.h> +#include <iprt/path.h> +#include <iprt/string.h> +#include <iprt/test.h> + + +static int testCreateTempDir(RTTEST hTest, const char *pszTestcase, char *pszTempDir, size_t cbTempDir) +{ + char szTempDir[RTPATH_MAX]; + int rc = RTPathTemp(szTempDir, sizeof(szTempDir)); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTPathAppend(szTempDir, sizeof(szTempDir), "tstClipboardTransfers"); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTDirCreate(szTempDir, 0700, 0); + if (rc == VERR_ALREADY_EXISTS) + rc = VINF_SUCCESS; + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTPathAppend(szTempDir, sizeof(szTempDir), "XXXXX"); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTDirCreateTemp(szTempDir, 0700); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTPathJoin(pszTempDir, cbTempDir, szTempDir, pszTestcase); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Created temporary directory: %s\n", pszTempDir); + + return rc; +} + +static int testRemoveTempDir(RTTEST hTest) +{ + char szTempDir[RTPATH_MAX]; + int rc = RTPathTemp(szTempDir, sizeof(szTempDir)); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTPathAppend(szTempDir, sizeof(szTempDir), "tstClipboardTransfers"); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + rc = RTDirRemoveRecursive(szTempDir, RTDIRRMREC_F_CONTENT_AND_DIR); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Removed temporary directory: %s\n", szTempDir); + + return rc; +} + +static int testCreateDir(RTTEST hTest, const char *pszPathToCreate) +{ + RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Creating directory: %s\n", pszPathToCreate); + + int rc = RTDirCreateFullPath(pszPathToCreate, 0700); + if (rc == VERR_ALREADY_EXISTS) + rc = VINF_SUCCESS; + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + + return rc; +} + +static int testCreateFile(RTTEST hTest, const char *pszTempDir, const char *pszFileName, uint32_t fOpen, size_t cbSize, + char **ppszFilePathAbs) +{ + char szFilePath[RTPATH_MAX]; + + int rc = RTStrCopy(szFilePath, sizeof(szFilePath), pszTempDir); + RTTESTI_CHECK_RC_OK_RET(rc, rc); + + rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszFileName); + RTTESTI_CHECK_RC_OK_RET(rc, rc); + + char *pszDirToCreate = RTStrDup(szFilePath); + RTTESTI_CHECK_RET(pszDirToCreate, VERR_NO_MEMORY); + + RTPathStripFilename(pszDirToCreate); + + rc = testCreateDir(hTest, pszDirToCreate); + RTTESTI_CHECK_RC_OK_RET(rc, rc); + + RTStrFree(pszDirToCreate); + pszDirToCreate = NULL; + + if (!fOpen) + fOpen = RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE; + + RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Creating file: %s\n", szFilePath); + + RTFILE hFile; + rc = RTFileOpen(&hFile, szFilePath, fOpen); + if (RT_SUCCESS(rc)) + { + if (cbSize) + { + /** @todo Fill in some random stuff. */ + } + + rc = RTFileClose(hFile); + RTTESTI_CHECK_RC_RET(rc, VINF_SUCCESS, rc); + } + + if (ppszFilePathAbs) + *ppszFilePathAbs = RTStrDup(szFilePath); + + return rc; +} + +typedef struct TESTTRANSFERROOTENTRY +{ + TESTTRANSFERROOTENTRY(const RTCString &a_strPath) + : strPath(a_strPath) { } + + RTCString strPath; +} TESTTRANSFERROOTENTRY; + +static int testAddRootEntry(RTTEST hTest, const char *pszTempDir, + const TESTTRANSFERROOTENTRY &rootEntry, char **ppszRoots) +{ + char *pszRoots = NULL; + + const char *pszPath = rootEntry.strPath.c_str(); + + char *pszPathAbs; + int rc = testCreateFile(hTest, pszTempDir, pszPath, 0, 0, &pszPathAbs); + RTTESTI_CHECK_RC_OK_RET(rc, rc); + + rc = RTStrAAppend(&pszRoots, pszPathAbs); + RTTESTI_CHECK_RC_OK(rc); + + rc = RTStrAAppend(&pszRoots, "\r\n"); + RTTESTI_CHECK_RC_OK(rc); + + RTStrFree(pszPathAbs); + + *ppszRoots = pszRoots; + + return rc; +} + +static int testAddRootEntries(RTTEST hTest, const char *pszTempDir, + RTCList<TESTTRANSFERROOTENTRY> &lstBase, RTCList<TESTTRANSFERROOTENTRY> lstToExtend, + char **ppszRoots) +{ + int rc = VINF_SUCCESS; + + char *pszRoots = NULL; + + for (size_t i = 0; i < lstBase.size(); ++i) + { + char *pszEntry = NULL; + rc = testAddRootEntry(hTest, pszTempDir, lstBase.at(i), &pszEntry); + RTTESTI_CHECK_RC_OK_BREAK(rc); + rc = RTStrAAppend(&pszRoots, pszEntry); + RTTESTI_CHECK_RC_OK_BREAK(rc); + RTStrFree(pszEntry); + } + + for (size_t i = 0; i < lstToExtend.size(); ++i) + { + char *pszEntry = NULL; + rc = testAddRootEntry(hTest, pszTempDir, lstToExtend.at(i), &pszEntry); + RTTESTI_CHECK_RC_OK_BREAK(rc); + rc = RTStrAAppend(&pszRoots, pszEntry); + RTTESTI_CHECK_RC_OK_BREAK(rc); + RTStrFree(pszEntry); + } + + if (RT_SUCCESS(rc)) + *ppszRoots = pszRoots; + + return rc; +} + +static void testTransferRootsSetSingle(RTTEST hTest, + RTCList<TESTTRANSFERROOTENTRY> &lstBase, RTCList<TESTTRANSFERROOTENTRY> lstToExtend, + int rcExpected) +{ + PSHCLTRANSFER pTransfer; + int rc = ShClTransferCreate(&pTransfer); + RTTESTI_CHECK_RC_OK(rc); + + char szTestTransferRootsSetDir[RTPATH_MAX]; + rc = testCreateTempDir(hTest, "testTransferRootsSet", szTestTransferRootsSetDir, sizeof(szTestTransferRootsSetDir)); + RTTESTI_CHECK_RC_OK_RETV(rc); + + /* This is the file we're trying to access (but not supposed to). */ + rc = testCreateFile(hTest, szTestTransferRootsSetDir, "must-not-access-this", 0, 0, NULL); + RTTESTI_CHECK_RC_OK(rc); + + char *pszRoots; + rc = testAddRootEntries(hTest, szTestTransferRootsSetDir, lstBase, lstToExtend, &pszRoots); + RTTESTI_CHECK_RC_OK_RETV(rc); + + rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1); + RTTESTI_CHECK_RC(rc, rcExpected); + + RTStrFree(pszRoots); + + rc = ShClTransferDestroy(pTransfer); + RTTESTI_CHECK_RC_OK(rc); +} + +static void testTransferObjOpenSingle(RTTEST hTest, + RTCList<TESTTRANSFERROOTENTRY> &lstRoots, const char *pszObjPath, int rcExpected) +{ + RT_NOREF(hTest); + + PSHCLTRANSFER pTransfer; + int rc = ShClTransferCreate(&pTransfer); + RTTESTI_CHECK_RC_OK(rc); + + rc = ShClTransferInit(pTransfer, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_LOCAL); + RTTESTI_CHECK_RC_OK(rc); + + char szTestTransferObjOpenDir[RTPATH_MAX]; + rc = testCreateTempDir(hTest, "testTransferObjOpen", szTestTransferObjOpenDir, sizeof(szTestTransferObjOpenDir)); + RTTESTI_CHECK_RC_OK_RETV(rc); + + /* This is the file we're trying to access (but not supposed to). */ + rc = testCreateFile(hTest, szTestTransferObjOpenDir, "file1.txt", 0, 0, NULL); + RTTESTI_CHECK_RC_OK(rc); + + RTCList<TESTTRANSFERROOTENTRY> lstToExtendEmpty; + + char *pszRoots; + rc = testAddRootEntries(hTest, szTestTransferObjOpenDir, lstRoots, lstToExtendEmpty, &pszRoots); + RTTESTI_CHECK_RC_OK_RETV(rc); + + rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1); + RTTESTI_CHECK_RC_OK(rc); + + RTStrFree(pszRoots); + + SHCLOBJOPENCREATEPARMS openCreateParms; + rc = ShClTransferObjOpenParmsInit(&openCreateParms); + RTTESTI_CHECK_RC_OK(rc); + + rc = RTStrCopy(openCreateParms.pszPath, openCreateParms.cbPath, pszObjPath); + RTTESTI_CHECK_RC_OK(rc); + + SHCLOBJHANDLE hObj; + rc = ShClTransferObjOpen(pTransfer, &openCreateParms, &hObj); + RTTESTI_CHECK_RC(rc, rcExpected); + if (RT_SUCCESS(rc)) + { + rc = ShClTransferObjClose(pTransfer, hObj); + RTTESTI_CHECK_RC_OK(rc); + } + + rc = ShClTransferDestroy(pTransfer); + RTTESTI_CHECK_RC_OK(rc); +} + +static void testTransferBasics(RTTEST hTest) +{ + RT_NOREF(hTest); + + RTTestISub("Testing transfer basics"); + + SHCLEVENTSOURCE Source; + int rc = ShClEventSourceCreate(&Source, 0); + RTTESTI_CHECK_RC_OK(rc); + rc = ShClEventSourceDestroy(&Source); + RTTESTI_CHECK_RC_OK(rc); + PSHCLTRANSFER pTransfer; + rc = ShClTransferCreate(&pTransfer); + RTTESTI_CHECK_RC_OK(rc); + rc = ShClTransferDestroy(pTransfer); + RTTESTI_CHECK_RC_OK(rc); +} + +static void testTransferRootsSet(RTTEST hTest) +{ + RTTestISub("Testing setting transfer roots"); + + /* Define the (valid) transfer root set. */ + RTCList<TESTTRANSFERROOTENTRY> lstBase; + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/file1.txt")); + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/file1.txt")); + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/sub1/file1.txt")); + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/file1.txt")); + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/sub1/file1.txt")); + + RTCList<TESTTRANSFERROOTENTRY> lstBreakout; + testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VINF_SUCCESS); + + lstBreakout.clear(); + lstBase.append(TESTTRANSFERROOTENTRY("../must-not-access-this")); + testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER); + + lstBreakout.clear(); + lstBase.append(TESTTRANSFERROOTENTRY("does-not-exist/file1.txt")); + testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER); + + lstBreakout.clear(); + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/../must-not-access-this")); + testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER); + + lstBreakout.clear(); + lstBase.append(TESTTRANSFERROOTENTRY("my-transfer-1/./../must-not-access-this")); + testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER); + + lstBreakout.clear(); + lstBase.append(TESTTRANSFERROOTENTRY("../does-not-exist")); + testTransferRootsSetSingle(hTest, lstBase, lstBreakout, VERR_INVALID_PARAMETER); +} + +static void testTransferObjOpen(RTTEST hTest) +{ + RTTestISub("Testing setting transfer object open"); + + /* Define the (valid) transfer root set. */ + RTCList<TESTTRANSFERROOTENTRY> lstRoots; + lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/file1.txt")); + lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/file1.txt")); + lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir1/sub1/file1.txt")); + lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/file1.txt")); + lstRoots.append(TESTTRANSFERROOTENTRY("my-transfer-1/dir2/sub1/file1.txt")); + + testTransferObjOpenSingle(hTest, lstRoots, "file1.txt", VINF_SUCCESS); + testTransferObjOpenSingle(hTest, lstRoots, "does-not-exist.txt", VERR_PATH_NOT_FOUND); + testTransferObjOpenSingle(hTest, lstRoots, "dir1/does-not-exist.txt", VERR_PATH_NOT_FOUND); + testTransferObjOpenSingle(hTest, lstRoots, "../must-not-access-this.txt", VERR_INVALID_PARAMETER); + testTransferObjOpenSingle(hTest, lstRoots, "dir1/../../must-not-access-this.txt", VERR_INVALID_PARAMETER); +} + +int main(int argc, char *argv[]) +{ + /* + * Init the runtime, test and say hello. + */ + const char *pcszExecName; + NOREF(argc); + pcszExecName = strrchr(argv[0], '/'); + pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0]; + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + testTransferBasics(hTest); + testTransferRootsSet(hTest); + testTransferObjOpen(hTest); + + int rc = testRemoveTempDir(hTest); + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); + + /* + * Summary + */ + return RTTestSummaryAndDestroy(hTest); +} + |