VirtualBox

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

Last change on this file since 76403 was 76403, checked in by vboxsync, 6 years ago

VBox/vmm/pdmdrv.h: Don't include err.h when it isn't needed. bugref:9344

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

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