VirtualBox

source: vbox/trunk/src/VBox/Devices/testcase/tstDeviceCfg.cpp@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.6 KB
Line 
1/* $Id: tstDeviceCfg.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * tstDevice - Configuration loader.
4 */
5
6/*
7 * Copyright (C) 2020-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_DEFAULT /** @todo */
33#include <VBox/types.h>
34#include <iprt/errcore.h>
35#include <iprt/json.h>
36#include <iprt/mem.h>
37#include <iprt/message.h>
38#include <iprt/string.h>
39
40#include "tstDeviceCfg.h"
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51
52
53/**
54 * Wrapper around RTErrInfoSetV / RTMsgErrorV.
55 *
56 * @returns @a rc
57 * @param pErrInfo Extended error info.
58 * @param rc The return code.
59 * @param pszFormat The message format.
60 * @param ... The message format arguments.
61 */
62static int tstDevCfgErrorRc(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...)
63{
64 va_list va;
65 va_start(va, pszFormat);
66 if (pErrInfo)
67 RTErrInfoSetV(pErrInfo, rc, pszFormat, va);
68 else
69 RTMsgErrorV(pszFormat, va);
70 va_end(va);
71 return rc;
72}
73
74
75/**
76 * Destroys the given configuration item array freeing all allocated resources.
77 *
78 * @returns nothing.
79 * @param paCfg The configuration item array to destroy.
80 * @param cCfgItems Number of items in the array.
81 */
82static void tstDevCfgItemsDestroy(PTSTDEVCFGITEM paCfg, uint32_t cCfgItems)
83{
84 RT_NOREF(paCfg, cCfgItems);
85}
86
87
88/**
89 * Loads the given string from the config, creating a duplicate.
90 *
91 * @returns VBox status code.
92 * @param hJsonTop The JSON top value handle containing the value to load.
93 * @param pszValName The value name.
94 * @param ppszValCopy Where to store the pointer to the value on success, must be freed with RTStrFree().
95 * @param fMissingOk Flag whether it is considered success if the value does not exist.
96 * @param pErrInfo Pointer to the error info to fill on error.
97 */
98static int tstDevCfgLoadString(RTJSONVAL hJsonTop, const char *pszValName, char **ppszValCopy, bool fMissingOk, PRTERRINFO pErrInfo)
99{
100 RTJSONVAL hJsonVal;
101 int rc = RTJsonValueQueryByName(hJsonTop, pszValName, &hJsonVal);
102 if (RT_SUCCESS(rc))
103 {
104 const char *pszVal = RTJsonValueGetString(hJsonVal);
105 if (RT_LIKELY(pszVal))
106 {
107 *ppszValCopy = RTStrDup(pszVal);
108 if (RT_UNLIKELY(!*ppszValCopy))
109 rc = tstDevCfgErrorRc(pErrInfo, VERR_NO_STR_MEMORY, "tstDevCfg/JSON: Out of memory allocating memory for value of \"%s\" ", pszValName);
110 }
111 else
112 rc = tstDevCfgErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "tstDevCfg/JSON: \"%s\" is not a string", pszValName);
113
114 RTJsonValueRelease(hJsonVal);
115 }
116 else if ( rc == VERR_NOT_FOUND
117 && fMissingOk)
118 {
119 *ppszValCopy = NULL;
120 rc = VINF_SUCCESS;
121 }
122 else
123 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"%s\"", pszValName);
124
125 return rc;
126}
127
128
129/**
130 * Loads a bool value using the given value name from the config.
131 *
132 * @returns VBox status code.
133 * @param hJsonTop The JSON top value handle containing the value to load.
134 * @param pszValName The value name.
135 * @param pf Where to store the value on success.
136 * @param pErrInfo Pointer to the error info to fill on error.
137 */
138static int tstDevCfgLoadBool(RTJSONVAL hJsonTop, const char *pszValName, bool *pf, PRTERRINFO pErrInfo)
139{
140 int rc = RTJsonValueQueryBooleanByName(hJsonTop, pszValName, pf);
141 if (RT_FAILURE(rc))
142 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query boolean value of \"%s\"", pszValName);
143
144 return rc;
145}
146
147
148/**
149 * Determines the config item type from the given.value.
150 *
151 * @returns VBox status code.
152 * @param hJsonTop The JSON top value handle containing the value to load.
153 * @param pszValName The value name.
154 * @param penmCfgItemType Where to store the determined config item type on success.
155 * @param pErrInfo Pointer to the error info to fill on error.
156 */
157static int tstDevCfgLoadCfgItemType(RTJSONVAL hJsonTop, const char *pszValName, PTSTDEVCFGITEMTYPE penmCfgItemType, PRTERRINFO pErrInfo)
158{
159 RTJSONVAL hJsonVal;
160 int rc = RTJsonValueQueryByName(hJsonTop, pszValName, &hJsonVal);
161 if (RT_SUCCESS(rc))
162 {
163 const char *pszVal = RTJsonValueGetString(hJsonVal);
164 if (!RTStrCmp(pszVal, "Integer"))
165 *penmCfgItemType = TSTDEVCFGITEMTYPE_INTEGER;
166 else if (!RTStrCmp(pszVal, "String"))
167 *penmCfgItemType = TSTDEVCFGITEMTYPE_STRING;
168 else
169 rc = tstDevCfgErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "tstDevCfg/JSON: \"%s\" is not a valid config item type", pszVal);
170
171 RTJsonValueRelease(hJsonVal);
172 }
173 else
174 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"%s\"", pszValName);
175
176 return rc;
177}
178
179
180/**
181 * Loads the config item value from the given config based on the earlier determined type.
182 *
183 * @returns VBox status code.
184 * @param hJsonTop The JSON top value handle containing the value to load.
185 * @param pszValName The value name.
186 * @param pCfg Where to store the retrieved config value.
187 * @param enmCfgItemType The earlier determined config item type.
188 * @param pErrInfo Pointer to the error info to fill on error.
189 */
190static int tstDevCfgLoadCfgItemValue(RTJSONVAL hJsonTop, const char *pszValName, PTSTDEVCFGITEM pCfg, TSTDEVCFGITEMTYPE enmCfgItemType, PRTERRINFO pErrInfo)
191{
192 RTJSONVAL hJsonVal;
193
194 int rc = RTJsonValueQueryByName(hJsonTop, pszValName, &hJsonVal);
195 if (RT_SUCCESS(rc))
196 {
197 RTJSONVALTYPE enmJsonType = RTJsonValueGetType(hJsonVal);
198
199 if ( ( enmJsonType == RTJSONVALTYPE_INTEGER
200 && enmCfgItemType == TSTDEVCFGITEMTYPE_INTEGER)
201 || ( enmJsonType == RTJSONVALTYPE_STRING
202 && enmCfgItemType == TSTDEVCFGITEMTYPE_STRING))
203 {
204 switch (enmCfgItemType)
205 {
206 case TSTDEVCFGITEMTYPE_INTEGER:
207 {
208 rc = RTJsonValueQueryInteger(hJsonVal, &pCfg->u.i64);
209 break;
210 }
211 case TSTDEVCFGITEMTYPE_STRING:
212 {
213 const char *psz = RTJsonValueGetString(hJsonVal);
214 AssertPtr(psz);
215
216 pCfg->u.psz = RTStrDup(psz);
217 if (RT_UNLIKELY(!pCfg->u.psz))
218 rc = VERR_NO_STR_MEMORY;
219 break;
220 }
221 default:
222 AssertFailed(); /* Should never ever get here. */
223 rc = tstDevCfgErrorRc(pErrInfo, VERR_INTERNAL_ERROR, "tstDevCfg/JSON: Invalid config item type %u", enmCfgItemType);
224 }
225
226 if (RT_SUCCESS(rc))
227 pCfg->enmType = enmCfgItemType;
228 else
229 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query config item value");
230 }
231 else
232 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: JSON value type doesn't match config item type (got %u, expected %u)", enmJsonType, enmCfgItemType);
233
234 RTJsonValueRelease(hJsonVal);
235 }
236 else
237 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"%s\"", pszValName);
238
239 return rc;
240}
241
242
243/**
244 * Loads the test configuration from the given JSON value.
245 *
246 * @returns VBox status code.
247 * @param paCfg The configuration array to fill.
248 * @param cCfgItems Number of configuration items.
249 * @param hJsonValCfg The JSON value to gather the config items from.
250 * @param pErrInfo Pointer to error info.
251 */
252static int tstDevCfgLoadTestCfgWorker(PTSTDEVCFGITEM paCfg, uint32_t cCfgItems, RTJSONVAL hJsonValCfg, PRTERRINFO pErrInfo)
253{
254 int rc = VINF_SUCCESS;
255
256 for (uint32_t i = 0; i < cCfgItems && RT_SUCCESS(rc); i++)
257 {
258 PTSTDEVCFGITEM pCfg = &paCfg[i];
259 RTJSONVAL hJsonCfg;
260
261 rc = RTJsonValueQueryByIndex(hJsonValCfg, i, &hJsonCfg);
262 if (RT_SUCCESS(rc))
263 {
264 TSTDEVCFGITEMTYPE enmCfgItemType;
265
266 rc = tstDevCfgLoadString(hJsonCfg, "Key", (char **)&pCfg->pszKey, false /*fMissingOk*/, pErrInfo);
267 if (RT_SUCCESS(rc))
268 rc = tstDevCfgLoadCfgItemType(hJsonCfg, "Type", &enmCfgItemType, pErrInfo);
269 if (RT_SUCCESS(rc))
270 rc = tstDevCfgLoadCfgItemValue(hJsonCfg, "Value", pCfg, enmCfgItemType, pErrInfo);
271 }
272 else
273 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query config item %u", i);
274 }
275
276 return rc;
277}
278
279
280/**
281 * Loads a single testcase from the given JSON config value.
282 *
283 * @returns VBox status code.
284 * @param ppszTestcaseId Where to store the testcase ID on success.
285 * @param pcTestcaseCfgItems Where to store the number of testcase config items on success.
286 * @param ppTestcaseCfg Where to store the testcase config on success.
287 * @param pErrInfo Pointer to error info.
288 */
289static int tstDevCfgLoadTestcase(RTJSONVAL hJsonTestcase, const char **ppszTestcaseId, uint32_t *pcTestcaseCfgItems, PCTSTDEVCFGITEM *ppTestcaseCfg, PRTERRINFO pErrInfo)
290{
291 char *pszTestcaseId = NULL;
292 int rc = tstDevCfgLoadString(hJsonTestcase, "Testcase", &pszTestcaseId, false /*fMissingOk*/, pErrInfo);
293 if (RT_SUCCESS(rc))
294 {
295 RTJSONVAL hJsonValCfg;
296 rc = RTJsonValueQueryByName(hJsonTestcase, "Config", &hJsonValCfg);
297 if (RT_SUCCESS(rc))
298 {
299 unsigned cCfgItems = 0;
300 rc = RTJsonValueQueryArraySize(hJsonValCfg, &cCfgItems);
301 if (RT_SUCCESS(rc))
302 {
303 if (cCfgItems > 0)
304 {
305 size_t cbCfg = sizeof(TSTDEVCFGITEM) * cCfgItems;
306 PTSTDEVCFGITEM paCfg = (PTSTDEVCFGITEM)RTMemAllocZ(cbCfg);
307 if (paCfg)
308 {
309 rc = tstDevCfgLoadTestCfgWorker(paCfg, cCfgItems, hJsonValCfg, pErrInfo);
310 if (RT_SUCCESS(rc))
311 {
312 *ppszTestcaseId = pszTestcaseId;
313 *pcTestcaseCfgItems = cCfgItems;
314 *ppTestcaseCfg = paCfg;
315 }
316 else /* Error already set, free test config structure. */
317 tstDevCfgItemsDestroy(paCfg, cCfgItems);
318 }
319 else
320 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to allocate %zu bytes for the test config structure", cbCfg);
321 }
322 else
323 {
324 *ppszTestcaseId = pszTestcaseId;
325 *pcTestcaseCfgItems = 0;
326 *ppTestcaseCfg = NULL;
327 }
328 }
329 else
330 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: \"Config\" is not an array");
331
332 RTJsonValueRelease(hJsonValCfg);
333 }
334 else
335 tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"Config\" value");
336
337 if (RT_FAILURE(rc))
338 RTStrFree(pszTestcaseId);
339 }
340
341 return rc;
342}
343
344
345/**
346 * Loads the testcase descriptions from the config.
347 *
348 * @returns VBox status code.
349 * @param pDevTest Where to store the testcases config on success.
350 * @param hJsonValTest Where to load the testcases config from.
351 * @param pErrInfo Pointer to error info.
352 */
353static int tstDevCfgLoadTestcases(PTSTDEVTEST pDevTest, RTJSONVAL hJsonValTest, PRTERRINFO pErrInfo)
354{
355 RTJSONVAL hJsonValTestcases;
356 int rc = RTJsonValueQueryByName(hJsonValTest, "Testcases", &hJsonValTestcases);
357 if (RT_SUCCESS(rc))
358 {
359 unsigned cTestcases = 0;
360 rc = RTJsonValueQueryArraySize(hJsonValTestcases, &cTestcases);
361 if (RT_SUCCESS(rc))
362 {
363 pDevTest->cTestcases = cTestcases;
364 if (cTestcases > 0)
365 {
366 size_t cbArray = sizeof(void *) * 2 * cTestcases + cTestcases * sizeof(uint32_t); /* One for the testcase ID and one for the associated configuration. */
367 uint8_t *pbTmp = (uint8_t *)RTMemAllocZ(cbArray);
368 if (pbTmp)
369 {
370 pDevTest->papszTestcaseIds = (const char **)pbTmp;
371 pDevTest->pacTestcaseCfgItems = (uint32_t *)&pDevTest->papszTestcaseIds[cTestcases];
372 pDevTest->papTestcaseCfg = (PCTSTDEVCFGITEM *)&pDevTest->pacTestcaseCfgItems[cTestcases];
373
374 for (uint32_t i = 0; i < cTestcases; i++)
375 {
376 RTJSONVAL hJsonTestcase;
377
378 rc = RTJsonValueQueryByIndex(hJsonValTestcases, i, &hJsonTestcase);
379 if (RT_SUCCESS(rc))
380 {
381 rc = tstDevCfgLoadTestcase(hJsonTestcase, &pDevTest->papszTestcaseIds[i],
382 &pDevTest->pacTestcaseCfgItems[i], &pDevTest->papTestcaseCfg[i], pErrInfo);
383 RTJsonValueRelease(hJsonTestcase);
384 }
385 else
386 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query testcase item %u", i);
387 }
388 }
389 else
390 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to allocate %zu bytes for the testcases", cbArray);
391 }
392 else
393 rc = tstDevCfgErrorRc(pErrInfo, VERR_INVALID_PARAMETER, "tstDevCfg/JSON: \"Testcases\" doesn't contain anything");
394 }
395 else
396 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: \"Testcases\" is not an array");
397
398 RTJsonValueRelease(hJsonValTestcases);
399 }
400 else
401 tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"Testcases\" value");
402
403 return rc;
404}
405
406
407/**
408 * Loads a test config from the given JSON object.
409 *
410 * @returns VBox status code.
411 * @param pDevTest Where to store the test config on success.
412 * @param hJsonValTest Where to load the test config from.
413 * @param pErrInfo Pointer to error info.
414 */
415static int tstDevCfgLoadTest(PTSTDEVTEST pDevTest, RTJSONVAL hJsonValTest, PRTERRINFO pErrInfo)
416{
417 int rc = tstDevCfgLoadBool(hJsonValTest, "R0Enabled", &pDevTest->fR0Enabled, pErrInfo);
418 if (RT_SUCCESS(rc))
419 rc = tstDevCfgLoadBool(hJsonValTest, "RCEnabled", &pDevTest->fRCEnabled, pErrInfo);
420
421 if (RT_SUCCESS(rc))
422 {
423 RTJSONVAL hJsonValCfg;
424 rc = RTJsonValueQueryByName(hJsonValTest, "Config", &hJsonValCfg);
425 if (RT_SUCCESS(rc))
426 {
427 unsigned cCfgItems = 0;
428 rc = RTJsonValueQueryArraySize(hJsonValCfg, &cCfgItems);
429 if (RT_SUCCESS(rc))
430 {
431 pDevTest->cCfgItems = cCfgItems;
432 if (cCfgItems > 0)
433 {
434 size_t cbCfg = sizeof(TSTDEVCFGITEM) * cCfgItems;
435 PTSTDEVCFGITEM paCfg = (PTSTDEVCFGITEM)RTMemAllocZ(cbCfg);
436 if (paCfg)
437 {
438 rc = tstDevCfgLoadTestCfgWorker(paCfg, cCfgItems, hJsonValCfg, pErrInfo);
439 if (RT_SUCCESS(rc))
440 pDevTest->paCfgItems = paCfg;
441 else /* Error already set, free test config structure. */
442 tstDevCfgItemsDestroy(paCfg, cCfgItems);
443 }
444 else
445 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to allocate %zu bytes for the test config structure", cbCfg);
446 }
447 }
448 else
449 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: \"Config\" is not an array");
450
451 RTJsonValueRelease(hJsonValCfg);
452 }
453 else
454 tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"Config\" value");
455 }
456
457 /* Load the test configs. */
458 if (RT_SUCCESS(rc))
459 rc = tstDevCfgLoadTestcases(pDevTest, hJsonValTest, pErrInfo);
460
461 return rc;
462}
463
464
465/**
466 * Configuration loader worker.
467 *
468 * @returns VBox status code.
469 * @param pDevTstCfg The test config structure to fill.
470 * @param hJsonRoot Handle of the root JSON value.
471 * @param hJsonValDeviceTests Handle to the test JSON array.
472 * @param pErrInfo Pointer to the error info.
473 */
474static int tstDevCfgLoadWorker(PTSTDEVCFG pDevTstCfg, RTJSONVAL hJsonRoot, RTJSONVAL hJsonValDeviceTests, PRTERRINFO pErrInfo)
475{
476 int rc = tstDevCfgLoadString(hJsonRoot, "PdmR3Module", (char **)&pDevTstCfg->pszPdmR3Mod, false /*fMissingOk*/, pErrInfo);
477 if (RT_SUCCESS(rc))
478 rc = tstDevCfgLoadString(hJsonRoot, "PdmR0Module", (char **)&pDevTstCfg->pszPdmR0Mod, true /*fMissingOk*/, pErrInfo);
479 if (RT_SUCCESS(rc))
480 rc = tstDevCfgLoadString(hJsonRoot, "PdmRCModule", (char **)&pDevTstCfg->pszPdmRCMod, true /*fMissingOk*/, pErrInfo);
481 if (RT_SUCCESS(rc))
482 rc = tstDevCfgLoadString(hJsonRoot, "TestcaseModule", (char **)&pDevTstCfg->pszTstDevMod, true /*fMissingOk*/, pErrInfo);
483 if (RT_SUCCESS(rc))
484 rc = tstDevCfgLoadString(hJsonRoot, "Device", (char **)&pDevTstCfg->pszDevName, false /*fMissingOk*/, pErrInfo);
485
486 if (RT_SUCCESS(rc))
487 {
488 /* Load the individual test configs. */
489 for (uint32_t idx = 0; idx < pDevTstCfg->cTests && RT_SUCCESS(rc); idx++)
490 {
491 RTJSONVAL hJsonValTest;
492
493 rc = RTJsonValueQueryByIndex(hJsonValDeviceTests, idx, &hJsonValTest);
494 if (RT_SUCCESS(rc))
495 {
496 rc = tstDevCfgLoadTest(&pDevTstCfg->aTests[idx], hJsonValTest, pErrInfo);
497 RTJsonValueRelease(hJsonValTest);
498 }
499 else
500 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query test %u from \"DeviceTests\"", idx);
501 }
502 }
503
504 return rc;
505}
506
507
508DECLHIDDEN(int) tstDevCfgLoad(const char *pszCfgFilename, PRTERRINFO pErrInfo, PCTSTDEVCFG *ppDevTstCfg)
509{
510 RTJSONVAL hJsonRoot;
511 int rc = RTJsonParseFromFile(&hJsonRoot, pszCfgFilename, pErrInfo);
512 if (RT_SUCCESS(rc))
513 {
514 RTJSONVAL hJsonValDeviceTests;
515
516 rc = RTJsonValueQueryByName(hJsonRoot, "DeviceTests", &hJsonValDeviceTests);
517 if (RT_SUCCESS(rc))
518 {
519 unsigned cTests = 0;
520 rc = RTJsonValueQueryArraySize(hJsonValDeviceTests, &cTests);
521 if (RT_SUCCESS(rc))
522 {
523 if (cTests > 0)
524 {
525 size_t cbTestCfg = RT_UOFFSETOF_DYN(TSTDEVCFG, aTests[cTests]);
526 PTSTDEVCFG pDevTstCfg = (PTSTDEVCFG)RTMemAllocZ(cbTestCfg);
527 if (pDevTstCfg)
528 {
529 pDevTstCfg->cTests = cTests;
530 rc = tstDevCfgLoadWorker(pDevTstCfg, hJsonRoot, hJsonValDeviceTests, pErrInfo);
531 if (RT_SUCCESS(rc))
532 *ppDevTstCfg = pDevTstCfg;
533 else /* Error already set, free test config structure. */
534 tstDevCfgDestroy(pDevTstCfg);
535 }
536 else
537 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to allocate %zu bytes for the test config structure", cbTestCfg);
538 }
539 else
540 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: \"DeviceTests\" is empty");
541 }
542 else
543 rc = tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: \"DeviceTests\" is not an array");
544
545 RTJsonValueRelease(hJsonValDeviceTests);
546 }
547 else
548 tstDevCfgErrorRc(pErrInfo, rc, "tstDevCfg/JSON: Failed to query \"DeviceTests\" value");
549
550 RTJsonValueRelease(hJsonRoot);
551 }
552
553 return rc;
554}
555
556
557DECLHIDDEN(void) tstDevCfgDestroy(PCTSTDEVCFG pDevTstCfg)
558{
559 RT_NOREF(pDevTstCfg);
560}
561
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use