VirtualBox

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

Last change on this file since 40205 was 40205, checked in by vboxsync, 13 years ago

Main: gcc warnings

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