VirtualBox

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

Last change on this file since 74910 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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