VirtualBox

source: vbox/trunk/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp@ 99180

Last change on this file since 99180 was 98526, checked in by vboxsync, 2 years ago

Guest Control: Initial commit (work in progress, disabled by default). bugref:9783

IGuestDirectory:

Added new attributes id + status + an own event source. Also added for rewind support via rewind().

New event types for guest directory [un]registration, state changes and entry reads.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: tstGuestCtrlParseBuffer.cpp 98526 2023-02-10 15:10:50Z vboxsync $ */
2/** @file
3 * Output stream parsing test cases.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_MAIN
33#include <VBox/err.h>
34#include <VBox/log.h>
35
36#include "../include/GuestCtrlImplPrivate.h"
37
38using namespace com;
39
40#include <iprt/env.h>
41#include <iprt/test.h>
42#include <iprt/stream.h>
43
44#ifndef BYTE
45# define BYTE uint8_t
46#endif
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52#define STR_SIZE(a_sz) RT_STR_TUPLE(a_sz)
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58typedef struct VBOXGUESTCTRL_BUFFER_VALUE
59{
60 char *pszValue;
61} VBOXGUESTCTRL_BUFFER_VALUE, *PVBOXGUESTCTRL_BUFFER_VALUE;
62typedef std::map< RTCString, VBOXGUESTCTRL_BUFFER_VALUE > GuestBufferMap;
63typedef std::map< RTCString, VBOXGUESTCTRL_BUFFER_VALUE >::iterator GuestBufferMapIter;
64typedef std::map< RTCString, VBOXGUESTCTRL_BUFFER_VALUE >::const_iterator GuestBufferMapIterConst;
65
66
67/*********************************************************************************************************************************
68* Global Variables *
69*********************************************************************************************************************************/
70char szUnterm1[] = { 'a', 's', 'd', 'f' };
71char szUnterm2[] = { 'f', 'o', 'o', '3', '=', 'b', 'a', 'r', '3' };
72
73static struct
74{
75 const char *pbData;
76 size_t cbData;
77 uint32_t offStart;
78 uint32_t offAfter;
79 uint32_t cMapElements;
80 int iResult;
81} g_aTestBlocks[] =
82{
83 /*
84 * Single object parsing.
85 * An object is represented by one or multiple key=value pairs which are
86 * separated by a single "\0". If this termination is missing it will be assumed
87 * that we need to collect more data to do a successful parsing.
88 */
89 /* Invalid stuff. */
90 { NULL, 0, 0, 0, 0, VERR_INVALID_POINTER },
91 { NULL, 512, 0, 0, 0, VERR_INVALID_POINTER },
92 { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER },
93 { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER },
94 { "foo=bar1", 0, 0, 0, 0, VERR_INVALID_PARAMETER },
95 { "foo=bar2", 0, 50, 50, 0, VERR_INVALID_PARAMETER },
96 /* Empty buffers. */
97 { "", 1, 0, 1, 0, VINF_SUCCESS },
98 { "\0", 1, 0, 1, 0, VINF_SUCCESS },
99 /* Unterminated values (missing "\0"). */
100 { STR_SIZE("test1"), 0, 0, 0, VERR_MORE_DATA },
101 { STR_SIZE("test2="), 0, 0, 0, VERR_MORE_DATA },
102 { STR_SIZE("test3=test3"), 0, 0, 0, VERR_MORE_DATA },
103 { STR_SIZE("test4=test4\0t41"), 0, sizeof("test4=test4\0") - 1, 1, VERR_MORE_DATA },
104 { STR_SIZE("test5=test5\0t51=t51"), 0, sizeof("test5=test5\0") - 1, 1, VERR_MORE_DATA },
105 /* Next block unterminated. */
106 { STR_SIZE("t51=t51\0t52=t52\0\0t53=t53"), 0, sizeof("t51=t51\0t52=t52\0") - 1, 2, VINF_SUCCESS },
107 { STR_SIZE("test6=test6\0\0t61=t61"), 0, sizeof("test6=test6\0") - 1, 1, VINF_SUCCESS },
108 /* Good stuff. */
109 { STR_SIZE("test61=\0test611=test611\0"), 0, sizeof("test61=\0test611=test611\0") - 1, 2, VINF_SUCCESS },
110 { STR_SIZE("test7=test7\0\0"), 0, sizeof("test7=test7\0") - 1, 1, VINF_SUCCESS },
111 { STR_SIZE("test8=test8\0t81=t81\0\0"), 0, sizeof("test8=test8\0t81=t81\0") - 1, 2, VINF_SUCCESS },
112 /* Good stuff, but with a second block -- should be *not* taken into account since
113 * we're only interested in parsing/handling the first object. */
114 { STR_SIZE("t9=t9\0t91=t91\0\0t92=t92\0\0"), 0, sizeof("t9=t9\0t91=t91\0") - 1, 2, VINF_SUCCESS },
115 /* Nasty stuff. */
116 /* iso 8859-1 encoding (?) of 'aou' all with diaeresis '=f' and 'ao' with diaeresis. */
117 { STR_SIZE("\xe4\xf6\xfc=\x66\xe4\xf6\0\0"), 0, sizeof("\xe4\xf6\xfc=\x66\xe4\xf6\0") - 1, 1, VINF_SUCCESS },
118 /* Like above, but after the first '\0' it adds 'ooo=aaa' all letters with diaeresis. */
119 { STR_SIZE("\xe4\xf6\xfc=\x66\xe4\xf6\0\xf6\xf6\xf6=\xe4\xe4\xe4"),
120 0, sizeof("\xe4\xf6\xfc=\x66\xe4\xf6\0") - 1, 1, VERR_MORE_DATA },
121 /* Some "real world" examples. */
122 { STR_SIZE("hdr_id=vbt_stat\0hdr_ver=1\0name=foo.txt\0\0"), 0, sizeof("hdr_id=vbt_stat\0hdr_ver=1\0name=foo.txt\0") - 1,
123 3, VINF_SUCCESS }
124};
125
126static struct
127{
128 const char *pbData;
129 size_t cbData;
130 /** Number of data blocks retrieved. These are separated by "\0\0". */
131 uint32_t cBlocks;
132 /** Overall result when done parsing. */
133 int iResult;
134} const g_aTestStream[] =
135{
136 /* No blocks. */
137 { "\0\0\0\0", sizeof("\0\0\0\0"), 0, VERR_NO_DATA },
138 /* Good stuff. */
139 { "\0b1=b1\0\0", sizeof("\0b1=b1\0\0"), 1, VERR_NO_DATA },
140 { "b1=b1\0\0", sizeof("b1=b1\0\0"), 1, VERR_NO_DATA },
141 { "b1=b1\0b2=b2\0\0", sizeof("b1=b1\0b2=b2\0\0"), 1, VERR_NO_DATA },
142 { "b1=b1\0b2=b2\0\0\0", sizeof("b1=b1\0b2=b2\0\0\0"), 1, VERR_NO_DATA }
143};
144
145int manualTest(void)
146{
147 int rc = VINF_SUCCESS;
148 static struct
149 {
150 const char *pbData;
151 size_t cbData;
152 uint32_t offStart;
153 uint32_t offAfter;
154 uint32_t cMapElements;
155 int iResult;
156 } const s_aTest[] =
157 {
158 { "test5=test5\0t51=t51", sizeof("test5=test5\0t51=t51"), 0, sizeof("test5=test5\0") - 1, 1, VERR_MORE_DATA },
159 { "\0\0test5=test5\0t51=t51", sizeof("\0\0test5=test5\0t51=t51"), 0, sizeof("\0\0test5=test5\0") - 1, 1, VERR_MORE_DATA },
160 };
161
162 for (unsigned iTest = 0; iTest < RT_ELEMENTS(s_aTest); iTest++)
163 {
164 RTTestIPrintf(RTTESTLVL_DEBUG, "Manual test #%d\n", iTest);
165
166 GuestToolboxStream stream;
167 rc = stream.AddData((BYTE *)s_aTest[iTest].pbData, s_aTest[iTest].cbData);
168
169 for (;;)
170 {
171 GuestToolboxStreamBlock block;
172 rc = stream.ParseBlock(block);
173 RTTestIPrintf(RTTESTLVL_DEBUG, "\tReturned with rc=%Rrc, numItems=%ld\n",
174 rc, block.GetCount());
175
176 if (block.GetCount())
177 break;
178 }
179 }
180
181 return rc;
182}
183
184int main()
185{
186 RTTEST hTest;
187 RTEXITCODE rcExit = RTTestInitAndCreate("tstParseBuffer", &hTest);
188 if (rcExit != RTEXITCODE_SUCCESS)
189 return rcExit;
190 RTTestBanner(hTest);
191
192 RTTestIPrintf(RTTESTLVL_DEBUG, "Initializing COM...\n");
193 HRESULT hrc = com::Initialize();
194 if (FAILED(hrc))
195 {
196 RTTestFailed(hTest, "Failed to initialize COM (%Rhrc)!\n", hrc);
197 return RTEXITCODE_FAILURE;
198 }
199
200#ifdef DEBUG_andy
201 int rc = manualTest();
202 if (RT_FAILURE(rc))
203 return RTEXITCODE_FAILURE;
204#endif
205
206 AssertCompile(sizeof("sizecheck") == 10);
207 AssertCompile(sizeof("off=rab") == 8);
208 AssertCompile(sizeof("off=rab\0\0") == 10);
209
210 RTTestSub(hTest, "Lines");
211 for (unsigned iTest = 0; iTest < RT_ELEMENTS(g_aTestBlocks); iTest++)
212 {
213 RTTestIPrintf(RTTESTLVL_DEBUG, "=> Test #%u\n", iTest);
214
215 GuestToolboxStream stream;
216 if (RT_FAILURE(g_aTestBlocks[iTest].iResult))
217 RTTestDisableAssertions(hTest);
218 int iResult = stream.AddData((BYTE *)g_aTestBlocks[iTest].pbData, g_aTestBlocks[iTest].cbData);
219 if (RT_FAILURE(g_aTestBlocks[iTest].iResult))
220 RTTestRestoreAssertions(hTest);
221 if (RT_SUCCESS(iResult))
222 {
223 GuestToolboxStreamBlock curBlock;
224 iResult = stream.ParseBlock(curBlock);
225 if (iResult != g_aTestBlocks[iTest].iResult)
226 RTTestFailed(hTest, "Block #%u: Returned %Rrc, expected %Rrc", iTest, iResult, g_aTestBlocks[iTest].iResult);
227 else if (stream.GetOffset() != g_aTestBlocks[iTest].offAfter)
228 RTTestFailed(hTest, "Block #%uOffset %zu wrong, expected %u\n",
229 iTest, stream.GetOffset(), g_aTestBlocks[iTest].offAfter);
230 else if (iResult == VERR_MORE_DATA)
231 RTTestIPrintf(RTTESTLVL_DEBUG, "\tMore data (Offset: %zu)\n", stream.GetOffset());
232
233 if (RT_SUCCESS(iResult) || iResult == VERR_MORE_DATA)
234 if (curBlock.GetCount() != g_aTestBlocks[iTest].cMapElements)
235 RTTestFailed(hTest, "Block #%u: Map has %u elements, expected %u\n",
236 iTest, curBlock.GetCount(), g_aTestBlocks[iTest].cMapElements);
237
238 /* There is remaining data left in the buffer (which needs to be merged
239 * with a following buffer) -- print it. */
240 size_t off = stream.GetOffset();
241 size_t cbToWrite = g_aTestBlocks[iTest].cbData - off;
242 if (cbToWrite)
243 {
244 RTTestIPrintf(RTTESTLVL_DEBUG, "\tRemaining (%u):\n", cbToWrite);
245
246 /* How to properly get the current RTTESTLVL (aka IPRT_TEST_MAX_LEVEL) here?
247 * Hack alert: Using RTEnvGet for now. */
248 if (!RTStrICmp(RTEnvGet("IPRT_TEST_MAX_LEVEL"), "debug"))
249 RTStrmWriteEx(g_pStdOut, &g_aTestBlocks[iTest].pbData[off], cbToWrite - 1, NULL);
250 }
251 }
252 }
253
254 RTTestSub(hTest, "Blocks");
255 for (unsigned iTest = 0; iTest < RT_ELEMENTS(g_aTestStream); iTest++)
256 {
257 RTTestIPrintf(RTTESTLVL_DEBUG, "=> Block test #%u\n", iTest);
258
259 GuestToolboxStream stream;
260 int iResult = stream.AddData((BYTE*)g_aTestStream[iTest].pbData, g_aTestStream[iTest].cbData);
261 if (RT_SUCCESS(iResult))
262 {
263 uint32_t cBlocks = 0;
264 uint8_t uSafeCouunter = 0;
265 do
266 {
267 GuestToolboxStreamBlock curBlock;
268 iResult = stream.ParseBlock(curBlock);
269 RTTestIPrintf(RTTESTLVL_DEBUG, "Block #%u: Returned with %Rrc", iTest, iResult);
270 if (RT_SUCCESS(iResult))
271 {
272 /* Only count block which have at least one pair. */
273 if (curBlock.GetCount())
274 cBlocks++;
275 }
276 if (uSafeCouunter++ > 32)
277 break;
278 } while (RT_SUCCESS(iResult));
279
280 if (iResult != g_aTestStream[iTest].iResult)
281 RTTestFailed(hTest, "Block #%uReturned %Rrc, expected %Rrc", iTest, iResult, g_aTestStream[iTest].iResult);
282 else if (cBlocks != g_aTestStream[iTest].cBlocks)
283 RTTestFailed(hTest, "Block #%uReturned %u blocks, expected %u", iTest, cBlocks, g_aTestStream[iTest].cBlocks);
284 }
285 else
286 RTTestFailed(hTest, "Block #%u: Adding data failed with %Rrc", iTest, iResult);
287 }
288
289 RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n");
290 com::Shutdown();
291
292 /*
293 * Summary.
294 */
295 return RTTestSummaryAndDestroy(hTest);
296}
297
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette