VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/test.cpp@ 99828

Last change on this file since 99828 was 99758, checked in by vboxsync, 21 months ago

IPRT: Make doxygen 1.9.6 happy. Mostly removing duplicate docs (iprt is documented in the header files). bugref:10442

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.3 KB
Line 
1/* $Id: test.cpp 99758 2023-05-11 21:37:59Z vboxsync $ */
2/** @file
3 * IPRT - Testcase Framework.
4 */
5
6/*
7 * Copyright (C) 2009-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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/test.h>
42
43#include <iprt/asm.h>
44#include <iprt/critsect.h>
45#include <iprt/env.h>
46#include <iprt/err.h>
47#include <iprt/file.h>
48#include <iprt/initterm.h>
49#include <iprt/mem.h>
50#include <iprt/once.h>
51#include <iprt/param.h>
52#include <iprt/pipe.h>
53#include <iprt/string.h>
54#include <iprt/stream.h>
55
56#include "internal/magics.h"
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62/**
63 * Guarded memory allocation record.
64 */
65typedef struct RTTESTGUARDEDMEM
66{
67 /** Pointer to the next record. */
68 struct RTTESTGUARDEDMEM *pNext;
69 /** The address we return to the user. */
70 void *pvUser;
71 /** The base address of the allocation. */
72 void *pvAlloc;
73 /** The size of the allocation. */
74 size_t cbAlloc;
75 /** Guards. */
76 struct
77 {
78 /** The guard address. */
79 void *pv;
80 /** The guard size. */
81 size_t cb;
82 } aGuards[2];
83} RTTESTGUARDEDMEM;
84/** Pointer to an guarded memory allocation. */
85typedef RTTESTGUARDEDMEM *PRTTESTGUARDEDMEM;
86
87/**
88 * Test instance structure.
89 */
90typedef struct RTTESTINT
91{
92 /** Magic. */
93 uint32_t u32Magic;
94 /** The number of errors. */
95 volatile uint32_t cErrors;
96 /** The test name. */
97 const char *pszTest;
98 /** The length of the test name. */
99 size_t cchTest;
100 /** The size of a guard. Multiple of PAGE_SIZE. */
101 uint32_t cbGuard;
102 /** The verbosity level. */
103 RTTESTLVL enmMaxLevel;
104 /** The creation flags. */
105 uint32_t fFlags;
106
107
108 /** Critical section serializing output. */
109 RTCRITSECT OutputLock;
110 /** The output stream. */
111 PRTSTREAM pOutStrm;
112 /** Whether we're currently at a newline. */
113 bool fNewLine;
114
115
116 /** Critical section serializing access to the members following it. */
117 RTCRITSECT Lock;
118
119 /** The list of guarded memory allocations. */
120 PRTTESTGUARDEDMEM pGuardedMem;
121
122 /** The current sub-test. */
123 const char *pszSubTest;
124 /** The length of the sub-test name. */
125 size_t cchSubTest;
126 /** Whether the current subtest should figure as 'SKIPPED'. */
127 bool fSubTestSkipped;
128 /** Whether we've reported the sub-test result or not. */
129 bool fSubTestReported;
130 /** The start error count of the current subtest. */
131 uint32_t cSubTestAtErrors;
132
133 /** The number of sub tests. */
134 uint32_t cSubTests;
135 /** The number of sub tests that failed. */
136 uint32_t cSubTestsFailed;
137
138 /** Error context message. */
139 char *pszErrCtx;
140
141 /** Set if XML output is enabled. */
142 bool fXmlEnabled;
143 /** Set if we omit the top level test in the XML report. */
144 bool fXmlOmitTopTest;
145 /** Set if we've reported the top test (for RTTEST_C_XML_DELAY_TOP_TEST). */
146 bool fXmlTopTestDone;
147 enum {
148 kXmlPos_ValueStart,
149 kXmlPos_Value,
150 kXmlPos_ElementEnd
151 } eXmlState;
152 /** Test pipe for the XML output stream going to the server. */
153 RTPIPE hXmlPipe;
154 /** File where the XML output stream might be directed. */
155 RTFILE hXmlFile;
156 /** The number of XML elements on the stack. */
157 size_t cXmlElements;
158 /** XML element stack. */
159 const char *apszXmlElements[10];
160
161 /** Number of times assertions has been disabled and quieted. */
162 uint32_t volatile cAssertionsDisabledAndQuieted;
163 /** Saved RTAssertSetQuiet return code. */
164 bool fAssertSavedQuiet;
165 /** Saved RTAssertSetMayPanic return code. */
166 bool fAssertSavedMayPanic;
167} RTTESTINT;
168/** Pointer to a test instance. */
169typedef RTTESTINT *PRTTESTINT;
170
171
172/*********************************************************************************************************************************
173* Defined Constants And Macros *
174*********************************************************************************************************************************/
175/** Validate a test instance. */
176#define RTTEST_VALID_RETURN(pTest) \
177 do { \
178 AssertPtrReturn(pTest, VERR_INVALID_HANDLE); \
179 AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, VERR_INVALID_HANDLE); \
180 } while (0)
181
182/** Gets and validates a test instance.
183 * If the handle is nil, we will try retrieve it from the test TLS entry.
184 */
185#define RTTEST_GET_VALID_RETURN(pTest) \
186 do { \
187 if (pTest == NIL_RTTEST) \
188 pTest = (PRTTESTINT)RTTlsGet(g_iTestTls); \
189 AssertPtrReturn(pTest, VERR_INVALID_HANDLE); \
190 AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, VERR_INVALID_MAGIC); \
191 } while (0)
192
193
194/** Gets and validates a test instance.
195 * If the handle is nil, we will try retrieve it from the test TLS entry.
196 */
197#define RTTEST_GET_VALID_RETURN_RC(pTest, rc) \
198 do { \
199 if (pTest == NIL_RTTEST) \
200 pTest = (PRTTESTINT)RTTlsGet(g_iTestTls); \
201 AssertPtrReturn(pTest, (rc)); \
202 AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, (rc)); \
203 } while (0)
204
205
206/*********************************************************************************************************************************
207* Internal Functions *
208*********************************************************************************************************************************/
209static void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem);
210static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...);
211static void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest);
212static void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va);
213static void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...);
214static void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va);
215static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...);
216static void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag);
217static void rtTestXmlEnd(PRTTESTINT pTest);
218
219
220/*********************************************************************************************************************************
221* Global Variables *
222*********************************************************************************************************************************/
223/** For serializing TLS init. */
224static RTONCE g_TestInitOnce = RTONCE_INITIALIZER;
225/** Our TLS entry. */
226static RTTLS g_iTestTls = NIL_RTTLS;
227
228
229
230/**
231 * Init TLS index once.
232 *
233 * @returns IPRT status code.
234 * @param pvUser Ignored.
235 */
236static DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser)
237{
238 NOREF(pvUser);
239 return RTTlsAllocEx(&g_iTestTls, NULL);
240}
241
242
243RTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel,
244 RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest)
245{
246 AssertReturn(!(fFlags & ~RTTEST_C_VALID_MASK), VERR_INVALID_PARAMETER);
247 AssertPtrNull(phTest);
248 AssertPtrNull(pszXmlFile);
249 /* RTTESTLVL_INVALID is valid! */
250 AssertReturn(enmMaxLevel >= RTTESTLVL_INVALID && enmMaxLevel < RTTESTLVL_END, VERR_INVALID_PARAMETER);
251
252 /*
253 * Global init.
254 */
255 int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL);
256 if (RT_FAILURE(rc))
257 return rc;
258
259 /*
260 * Create the instance.
261 */
262 PRTTESTINT pTest = (PRTTESTINT)RTMemAllocZ(sizeof(*pTest));
263 if (!pTest)
264 return VERR_NO_MEMORY;
265 pTest->u32Magic = RTTESTINT_MAGIC;
266 pTest->pszTest = RTStrDup(pszTest);
267 pTest->cchTest = strlen(pszTest);
268 pTest->cbGuard = PAGE_SIZE * 7;
269 pTest->enmMaxLevel = enmMaxLevel == RTTESTLVL_INVALID ? RTTESTLVL_INFO : enmMaxLevel;
270 pTest->fFlags = fFlags;
271
272 pTest->pOutStrm = g_pStdOut;
273 pTest->fNewLine = true;
274
275 pTest->pGuardedMem = NULL;
276
277 pTest->pszSubTest = NULL;
278 pTest->cchSubTest = 0;
279 pTest->fSubTestSkipped = false;
280 pTest->fSubTestReported = true;
281 pTest->cSubTestAtErrors = 0;
282 pTest->cSubTests = 0;
283 pTest->cSubTestsFailed = 0;
284
285 pTest->fXmlEnabled = false;
286 pTest->fXmlTopTestDone = false;
287 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
288 pTest->hXmlPipe = NIL_RTPIPE;
289 pTest->hXmlFile = NIL_RTFILE;
290 pTest->cXmlElements = 0;
291 pTest->cAssertionsDisabledAndQuieted = 0;
292 pTest->fAssertSavedMayPanic = true;
293 pTest->fAssertSavedQuiet = false;
294
295 rc = RTCritSectInit(&pTest->Lock);
296 if (RT_SUCCESS(rc))
297 {
298 rc = RTCritSectInit(&pTest->OutputLock);
299 if (RT_SUCCESS(rc))
300 {
301 /*
302 * Associate it with our TLS entry unless there is already
303 * an instance there.
304 */
305 if ( !(fFlags & RTTEST_C_NO_TLS)
306 && !RTTlsGet(g_iTestTls))
307 rc = RTTlsSet(g_iTestTls, pTest);
308 if (RT_SUCCESS(rc))
309 {
310 /*
311 * Output level override?
312 */
313 char szEnvVal[RTPATH_MAX];
314 if ((fFlags & RTTEST_C_USE_ENV) && enmMaxLevel == RTTESTLVL_INVALID)
315 {
316 rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szEnvVal, sizeof(szEnvVal), NULL);
317 if (RT_SUCCESS(rc))
318 {
319 char *pszMaxLevel = RTStrStrip(szEnvVal);
320 if (!strcmp(pszMaxLevel, "all"))
321 pTest->enmMaxLevel = RTTESTLVL_DEBUG;
322 if (!strcmp(pszMaxLevel, "quiet"))
323 pTest->enmMaxLevel = RTTESTLVL_FAILURE;
324 else if (!strcmp(pszMaxLevel, "debug"))
325 pTest->enmMaxLevel = RTTESTLVL_DEBUG;
326 else if (!strcmp(pszMaxLevel, "info"))
327 pTest->enmMaxLevel = RTTESTLVL_INFO;
328 else if (!strcmp(pszMaxLevel, "sub_test"))
329 pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
330 else if (!strcmp(pszMaxLevel, "failure"))
331 pTest->enmMaxLevel = RTTESTLVL_FAILURE;
332 }
333 else if (rc != VERR_ENV_VAR_NOT_FOUND)
334 RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc);
335 }
336
337 /*
338 * Any test driver we are connected or should connect to?
339 */
340 if (!(fFlags & RTTEST_C_NO_XML_REPORTING_PIPE))
341 {
342 if ( (fFlags & RTTEST_C_USE_ENV)
343 && iNativeTestPipe == -1)
344 {
345 rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_PIPE", szEnvVal, sizeof(szEnvVal), NULL);
346 if (RT_SUCCESS(rc))
347 {
348#if ARCH_BITS == 64
349 rc = RTStrToInt64Full(szEnvVal, 0, &iNativeTestPipe);
350#else
351 rc = RTStrToInt32Full(szEnvVal, 0, &iNativeTestPipe);
352#endif
353 if (RT_FAILURE(rc))
354 {
355 RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTStrToInt32Full(\"%s\") -> %Rrc\n",
356 pszTest, szEnvVal, rc);
357 iNativeTestPipe = -1;
358 }
359 }
360 else if (rc != VERR_ENV_VAR_NOT_FOUND)
361 RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_PIPE) -> %Rrc\n", pszTest, rc);
362 }
363 if (iNativeTestPipe != -1)
364 {
365 rc = RTPipeFromNative(&pTest->hXmlPipe, iNativeTestPipe, RTPIPE_N_WRITE);
366 if (RT_SUCCESS(rc))
367 pTest->fXmlEnabled = true;
368 else
369 {
370 RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTPipeFromNative(,%p,WRITE) -> %Rrc\n",
371 pszTest, iNativeTestPipe, rc);
372 pTest->hXmlPipe = NIL_RTPIPE;
373 }
374 }
375 }
376
377 /*
378 * Any test file we should write the test report to?
379 */
380 if (!(fFlags & RTTEST_C_NO_XML_REPORTING_FILE))
381 {
382 if ((fFlags & RTTEST_C_USE_ENV) && pszXmlFile == NULL)
383 {
384 rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_FILE", szEnvVal, sizeof(szEnvVal), NULL);
385 if (RT_SUCCESS(rc))
386 pszXmlFile = szEnvVal;
387 else if (rc != VERR_ENV_VAR_NOT_FOUND)
388 RTStrmPrintf(g_pStdErr, "%s: test file error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc);
389 }
390 if (pszXmlFile && *pszXmlFile)
391 {
392 rc = RTFileOpen(&pTest->hXmlFile, pszXmlFile,
393 RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE);
394 if (RT_SUCCESS(rc))
395 pTest->fXmlEnabled = true;
396 else
397 {
398 RTStrmPrintf(g_pStdErr, "%s: test file error: RTFileOpen(,\"%s\",) -> %Rrc\n",
399 pszTest, pszXmlFile, rc);
400 pTest->hXmlFile = NIL_RTFILE;
401 }
402 }
403 }
404
405 /*
406 * What do we report in the XML stream/file.?
407 */
408 pTest->fXmlOmitTopTest = (fFlags & RTTEST_C_XML_OMIT_TOP_TEST)
409 || ( (fFlags & RTTEST_C_USE_ENV)
410 && RTEnvExistEx(RTENV_DEFAULT, "IPRT_TEST_OMIT_TOP_TEST"));
411
412 /*
413 * Tell the test driver that we're up to.
414 */
415 rtTestXmlStart(pTest, pszTest);
416
417 *phTest = pTest;
418 return VINF_SUCCESS;
419 }
420
421 /* bail out. */
422 RTCritSectDelete(&pTest->OutputLock);
423 }
424 RTCritSectDelete(&pTest->Lock);
425 }
426 pTest->u32Magic = 0;
427 RTStrFree((char *)pTest->pszTest);
428 RTMemFree(pTest);
429 return rc;
430}
431
432
433RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
434{
435 return RTTestCreateEx(pszTest, RTTEST_C_USE_ENV, RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, NULL /*pszXmlFile*/, phTest);
436}
437
438
439RTR3DECL(int) RTTestCreateChild(const char *pszTest, PRTTEST phTest)
440{
441 return RTTestCreateEx(pszTest, RTTEST_C_USE_ENV | RTTEST_C_NO_XML_REPORTING,
442 RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, NULL /*pszXmlFile*/, phTest);
443}
444
445
446RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest)
447{
448 int rc = RTR3InitExeNoArguments(0);
449 if (RT_FAILURE(rc))
450 {
451 RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExeNoArguments failed with rc=%Rrc\n", pszTest, rc);
452 return RTEXITCODE_INIT;
453 }
454
455 rc = RTTestCreate(pszTest, phTest);
456 if (RT_FAILURE(rc))
457 {
458 RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc);
459 return RTEXITCODE_INIT;
460 }
461 return RTEXITCODE_SUCCESS;
462}
463
464
465RTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***ppapszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest)
466{
467 int rc;
468 if (cArgs <= 0 && ppapszArgs == NULL)
469 rc = RTR3InitExeNoArguments(fRtInit);
470 else
471 rc = RTR3InitExe(cArgs, ppapszArgs, fRtInit);
472 if (RT_FAILURE(rc))
473 {
474 RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExe(,,%#x) failed with rc=%Rrc\n", pszTest, fRtInit, rc);
475 return RTEXITCODE_INIT;
476 }
477
478 rc = RTTestCreate(pszTest, phTest);
479 if (RT_FAILURE(rc))
480 {
481 RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc);
482 return RTEXITCODE_INIT;
483 }
484 return RTEXITCODE_SUCCESS;
485}
486
487
488RTR3DECL(int) RTTestDestroy(RTTEST hTest)
489{
490 /*
491 * Validate
492 */
493 if (hTest == NIL_RTTEST)
494 return VINF_SUCCESS;
495 RTTESTINT *pTest = hTest;
496 RTTEST_VALID_RETURN(pTest);
497
498 /*
499 * Make sure we end with a new line and have finished up the XML.
500 */
501 if (!pTest->fNewLine)
502 rtTestPrintf(pTest, "\n");
503 rtTestXmlEnd(pTest);
504
505 /*
506 * Clean up.
507 */
508 if ((RTTESTINT *)RTTlsGet(g_iTestTls) == pTest)
509 RTTlsSet(g_iTestTls, NULL);
510
511 ASMAtomicWriteU32(&pTest->u32Magic, ~RTTESTINT_MAGIC);
512 RTCritSectDelete(&pTest->Lock);
513 RTCritSectDelete(&pTest->OutputLock);
514
515 /* free guarded memory. */
516 PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem;
517 pTest->pGuardedMem = NULL;
518 while (pMem)
519 {
520 PRTTESTGUARDEDMEM pFree = pMem;
521 pMem = pMem->pNext;
522 rtTestGuardedFreeOne(pFree);
523 }
524
525 RTStrFree((char *)pTest->pszSubTest);
526 pTest->pszSubTest = NULL;
527 RTStrFree((char *)pTest->pszTest);
528 pTest->pszTest = NULL;
529 RTStrFree(pTest->pszErrCtx);
530 pTest->pszErrCtx = NULL;
531 RTMemFree(pTest);
532 return VINF_SUCCESS;
533}
534
535
536RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest)
537{
538 if (phOldTest)
539 *phOldTest = (RTTEST)RTTlsGet(g_iTestTls);
540 return RTTlsSet(g_iTestTls, hNewDefaultTest);
541}
542
543
544RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName)
545{
546 PRTTESTINT pTest = hTest;
547 RTTEST_GET_VALID_RETURN(pTest);
548 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
549 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
550
551 size_t cchName = strlen(pszName);
552 AssertReturn(cchName < 128, VERR_INVALID_PARAMETER);
553 char *pszDupName = RTStrDup(pszName);
554 if (!pszDupName)
555 return VERR_NO_STR_MEMORY;
556
557 RTCritSectEnter(&pTest->Lock);
558 RTCritSectEnter(&pTest->OutputLock);
559
560 char *pszOldName = (char *)pTest->pszTest;
561 pTest->pszTest = pszDupName;
562 pTest->cchTest = cchName;
563
564 RTCritSectLeave(&pTest->OutputLock);
565 RTCritSectLeave(&pTest->Lock);
566
567 RTStrFree(pszOldName);
568 return VINF_SUCCESS;
569}
570
571
572RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser)
573{
574 PRTTESTINT pTest = hTest;
575 RTTEST_GET_VALID_RETURN(pTest);
576 if (cbAlign == 0)
577 cbAlign = 1;
578 AssertReturn(cbAlign <= PAGE_SIZE, VERR_INVALID_PARAMETER);
579 AssertReturn(cbAlign == (UINT32_C(1) << (ASMBitFirstSetU32(cbAlign) - 1)), VERR_INVALID_PARAMETER);
580
581 /*
582 * Allocate the record and block and initialize them.
583 */
584 int rc = VERR_NO_MEMORY;
585 PRTTESTGUARDEDMEM pMem = (PRTTESTGUARDEDMEM)RTMemAlloc(sizeof(*pMem));
586 if (RT_LIKELY(pMem))
587 {
588 size_t const cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
589 pMem->aGuards[0].cb = pMem->aGuards[1].cb = pTest->cbGuard;
590 pMem->cbAlloc = pMem->aGuards[0].cb + pMem->aGuards[1].cb + cbAligned;
591 pMem->pvAlloc = RTMemPageAlloc(pMem->cbAlloc);
592 if (pMem->pvAlloc)
593 {
594 pMem->aGuards[0].pv = pMem->pvAlloc;
595 pMem->pvUser = (uint8_t *)pMem->pvAlloc + pMem->aGuards[0].cb;
596 pMem->aGuards[1].pv = (uint8_t *)pMem->pvUser + cbAligned;
597 if (!fHead)
598 {
599 size_t off = cb & PAGE_OFFSET_MASK;
600 if (off)
601 {
602 off = PAGE_SIZE - RT_ALIGN_Z(off, cbAlign);
603 pMem->pvUser = (uint8_t *)pMem->pvUser + off;
604 }
605 }
606
607 /*
608 * Set up the guards and link the record.
609 */
610 ASMMemFill32(pMem->aGuards[0].pv, pMem->aGuards[0].cb, 0xdeadbeef);
611 ASMMemFill32(pMem->aGuards[1].pv, pMem->aGuards[1].cb, 0xdeadbeef);
612 rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_NONE);
613 if (RT_SUCCESS(rc))
614 {
615 rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_NONE);
616 if (RT_SUCCESS(rc))
617 {
618 *ppvUser = pMem->pvUser;
619
620 RTCritSectEnter(&pTest->Lock);
621 pMem->pNext = pTest->pGuardedMem;
622 pTest->pGuardedMem = pMem;
623 RTCritSectLeave(&pTest->Lock);
624
625 return VINF_SUCCESS;
626 }
627
628 RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ);
629 }
630
631 RTMemPageFree(pMem->pvAlloc, pMem->cbAlloc);
632 }
633 RTMemFree(pMem);
634 }
635 return rc;
636}
637
638
639RTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb)
640{
641 void *pvUser;
642 int rc = RTTestGuardedAlloc(hTest, cb, 1 /* cbAlign */, false /* fHead */, &pvUser);
643 if (RT_SUCCESS(rc))
644 return pvUser;
645 return NULL;
646}
647
648
649RTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb)
650{
651 void *pvUser;
652 int rc = RTTestGuardedAlloc(hTest, cb, 1 /* cbAlign */, true /* fHead */, &pvUser);
653 if (RT_SUCCESS(rc))
654 return pvUser;
655 return NULL;
656}
657
658
659/**
660 * Frees one block of guarded memory.
661 *
662 * The caller is responsible for unlinking it.
663 *
664 * @param pMem The memory record.
665 */
666static void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem)
667{
668 int rc;
669 rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
670 rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
671 RTMemPageFree(pMem->pvAlloc, pMem->cbAlloc);
672 RTMemFree(pMem);
673}
674
675
676RTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv)
677{
678 PRTTESTINT pTest = hTest;
679 RTTEST_GET_VALID_RETURN(pTest);
680 if (!pv)
681 return VINF_SUCCESS;
682
683 /*
684 * Find it.
685 */
686 int rc = VERR_INVALID_POINTER;
687 PRTTESTGUARDEDMEM pPrev = NULL;
688
689 RTCritSectEnter(&pTest->Lock);
690 for (PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem; pMem; pMem = pMem->pNext)
691 {
692 if (pMem->pvUser == pv)
693 {
694 if (pPrev)
695 pPrev->pNext = pMem->pNext;
696 else
697 pTest->pGuardedMem = pMem->pNext;
698 rtTestGuardedFreeOne(pMem);
699 rc = VINF_SUCCESS;
700 break;
701 }
702 pPrev = pMem;
703 }
704 RTCritSectLeave(&pTest->Lock);
705
706 return rc;
707}
708
709
710/**
711 * Outputs the formatted XML.
712 *
713 * @param pTest The test instance.
714 * @param pszFormat The format string.
715 * @param va The format arguments.
716 */
717static void rtTestXmlOutputV(PRTTESTINT pTest, const char *pszFormat, va_list va)
718{
719 if (pTest->fXmlEnabled)
720 {
721 char *pszStr;
722 ssize_t cchStr = RTStrAPrintfV(&pszStr, pszFormat, va);
723 if (pszStr)
724 {
725 if (pTest->hXmlPipe != NIL_RTPIPE)
726 RTPipeWriteBlocking(pTest->hXmlPipe, pszStr, cchStr, NULL);
727 if (pTest->hXmlFile != NIL_RTFILE)
728 RTFileWrite(pTest->hXmlFile, pszStr, cchStr, NULL);
729 RTStrFree(pszStr);
730 }
731 }
732}
733
734
735/**
736 * Outputs the formatted XML.
737 *
738 * @param pTest The test instance.
739 * @param pszFormat The format string.
740 * @param ... The format arguments.
741 */
742static void rtTestXmlOutput(PRTTESTINT pTest, const char *pszFormat, ...)
743{
744 va_list va;
745 va_start(va, pszFormat);
746 rtTestXmlOutputV(pTest, pszFormat, va);
747 va_end(va);
748}
749
750
751/**
752 * Starts the XML stream.
753 *
754 * @param pTest The test instance.
755 * @param pszTest The test name.
756 */
757static void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest)
758{
759 pTest->cXmlElements = 0;
760 if (pTest->fXmlEnabled)
761 {
762 rtTestXmlOutput(pTest, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
763 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
764 pTest->fXmlTopTestDone = !(pTest->fFlags & RTTEST_C_XML_DELAY_TOP_TEST) || pTest->fXmlOmitTopTest;
765 if (pTest->fXmlTopTestDone && !pTest->fXmlOmitTopTest)
766 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest);
767 }
768}
769
770
771/**
772 * Emit an XML element that doesn't have any value and instead ends immediately.
773 *
774 * The caller must own the instance lock.
775 *
776 * @param pTest The test instance.
777 * @param pszTag The element tag.
778 * @param pszAttrFmt The element attributes as a format string. Use
779 * NULL if none.
780 * @param va Format string arguments.
781 */
782static void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
783{
784 if (pTest->fXmlEnabled)
785 {
786 RTTIMESPEC TimeSpec;
787 RTTIME Time;
788 char szTS[80];
789 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
790
791 if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
792 rtTestXmlOutput(pTest, "\n");
793
794 if (!pszAttrFmt || !*pszAttrFmt)
795 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas/>\n",
796 pTest->cXmlElements * 2, "", pszTag, szTS);
797 else
798 {
799 va_list va2;
800 va_copy(va2, va);
801 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N/>\n",
802 pTest->cXmlElements * 2, "", pszTag, szTS, pszAttrFmt, &va2);
803 va_end(va2);
804 }
805 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
806 }
807}
808
809
810/**
811 * Wrapper around rtTestXmlElemV.
812 */
813static void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
814{
815 va_list va;
816 va_start(va, pszAttrFmt);
817 rtTestXmlElemV(pTest, pszTag, pszAttrFmt, va);
818 va_end(va);
819}
820
821
822/**
823 * Starts a new XML element.
824 *
825 * The caller must own the instance lock.
826 *
827 * @param pTest The test instance.
828 * @param pszTag The element tag.
829 * @param pszAttrFmt The element attributes as a format string. Use
830 * NULL if none.
831 * @param va Format string arguments.
832 */
833static void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
834{
835 /* Push it onto the stack. */
836 size_t i = pTest->cXmlElements;
837 AssertReturnVoid(i < RT_ELEMENTS(pTest->apszXmlElements));
838 pTest->apszXmlElements[i] = pszTag;
839 pTest->cXmlElements = i + 1;
840
841 if (pTest->fXmlEnabled)
842 {
843 RTTIMESPEC TimeSpec;
844 RTTIME Time;
845 char szTS[80];
846 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
847
848 if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
849 rtTestXmlOutput(pTest, "\n");
850
851 if (!pszAttrFmt || !*pszAttrFmt)
852 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas>",
853 i * 2, "", pszTag, szTS);
854 else
855 {
856 va_list va2;
857 va_copy(va2, va);
858 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N>",
859 i * 2, "", pszTag, szTS, pszAttrFmt, &va2);
860 va_end(va2);
861 }
862 pTest->eXmlState = RTTESTINT::kXmlPos_ValueStart;
863 }
864}
865
866
867/**
868 * Wrapper around rtTestXmlElemStartV.
869 */
870static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
871{
872 va_list va;
873 va_start(va, pszAttrFmt);
874 rtTestXmlElemStartV(pTest, pszTag, pszAttrFmt, va);
875 va_end(va);
876}
877
878
879/**
880 * Ends the current element.
881 *
882 * The caller must own the instance lock.
883 *
884 * @param pTest The test instance.
885 * @param pszTag The tag we're ending (chiefly for sanity
886 * checking).
887 */
888static void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag)
889{
890 /* pop the element */
891 size_t i = pTest->cXmlElements;
892 AssertReturnVoid(i > 0);
893 i--;
894 AssertReturnVoid(!strcmp(pszTag, pTest->apszXmlElements[i]));
895 pTest->cXmlElements = i;
896
897 /* Do the closing. */
898 if (pTest->fXmlEnabled)
899 {
900 if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
901 rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
902 else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
903 rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
904 else
905 rtTestXmlOutput(pTest, "</%s>\n", pszTag);
906 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
907 }
908}
909
910
911/**
912 * Ends the XML stream, closing all open elements.
913 *
914 * The caller must own the instance lock.
915 *
916 * @param pTest The test instance.
917 */
918static void rtTestXmlEnd(PRTTESTINT pTest)
919{
920 if (pTest->fXmlEnabled)
921 {
922 /*
923 * Close all the elements and add the final TestEnd one to get a
924 * final timestamp and some certainty that the XML is valid.
925 */
926 size_t i = pTest->cXmlElements;
927 AssertReturnVoid(i > 0 || pTest->fXmlOmitTopTest || !pTest->fXmlTopTestDone);
928 while (i-- > 1)
929 {
930 const char *pszTag = pTest->apszXmlElements[pTest->cXmlElements];
931 if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
932 rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
933 else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
934 rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
935 else
936 rtTestXmlOutput(pTest, "</%s>\n", pszTag);
937 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
938 }
939
940 if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone)
941 {
942 rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"",
943 pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors);
944 rtTestXmlOutput(pTest, "</Test>\n");
945 }
946
947 /*
948 * Close the XML outputs.
949 */
950 if (pTest->hXmlPipe != NIL_RTPIPE)
951 {
952 RTPipeClose(pTest->hXmlPipe);
953 pTest->hXmlPipe = NIL_RTPIPE;
954 }
955 if (pTest->hXmlFile != NIL_RTFILE)
956 {
957 RTFileClose(pTest->hXmlFile);
958 pTest->hXmlFile = NIL_RTFILE;
959 }
960 pTest->fXmlEnabled = false;
961 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
962 }
963 pTest->cXmlElements = 0;
964}
965
966/**
967 * Output callback.
968 *
969 * @returns number of bytes written.
970 * @param pvArg User argument.
971 * @param pachChars Pointer to an array of utf-8 characters.
972 * @param cbChars Number of bytes in the character array pointed to by pachChars.
973 */
974static DECLCALLBACK(size_t) rtTestPrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
975{
976 size_t cch = 0;
977 PRTTESTINT pTest = (PRTTESTINT)pvArg;
978 if (cbChars)
979 {
980 do
981 {
982 /* insert prefix if at a newline. */
983 if (pTest->fNewLine)
984 {
985 RTStrmWrite(pTest->pOutStrm, pTest->pszTest, pTest->cchTest);
986 RTStrmWrite(pTest->pOutStrm, ": ", 2);
987 cch += 2 + pTest->cchTest;
988 }
989
990 /* look for newline and write the stuff. */
991 const char *pchEnd = (const char *)memchr(pachChars, '\n', cbChars);
992 if (!pchEnd)
993 {
994 pTest->fNewLine = false;
995 RTStrmWrite(pTest->pOutStrm, pachChars, cbChars);
996 cch += cbChars;
997 break;
998 }
999
1000 pTest->fNewLine = true;
1001 size_t const cchPart = pchEnd - pachChars + 1;
1002 RTStrmWrite(pTest->pOutStrm, pachChars, cchPart);
1003 cch += cchPart;
1004 pachChars += cchPart;
1005 cbChars -= cchPart;
1006 } while (cbChars);
1007 }
1008 else
1009 RTStrmFlush(pTest->pOutStrm);
1010 return cch;
1011}
1012
1013
1014/**
1015 * Internal output worker.
1016 *
1017 * Caller takes the lock.
1018 *
1019 * @returns Number of chars printed.
1020 * @param pTest The test instance.
1021 * @param pszFormat The message.
1022 * @param va The arguments.
1023 */
1024static int rtTestPrintfV(PRTTESTINT pTest, const char *pszFormat, va_list va)
1025{
1026 return (int)RTStrFormatV(rtTestPrintfOutput, pTest, NULL, NULL, pszFormat, va);
1027}
1028
1029
1030/**
1031 * Internal output worker.
1032 *
1033 * Caller takes the lock.
1034 *
1035 * @returns Number of chars printed.
1036 * @param pTest The test instance.
1037 * @param pszFormat The message.
1038 * @param ... The arguments.
1039 */
1040static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...)
1041{
1042 va_list va;
1043
1044 va_start(va, pszFormat);
1045 int cch = rtTestPrintfV(pTest, pszFormat, va);
1046 va_end(va);
1047
1048 return cch;
1049}
1050
1051
1052RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
1053{
1054 PRTTESTINT pTest = hTest;
1055 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1056
1057 RTCritSectEnter(&pTest->OutputLock);
1058
1059 int cch = 0;
1060 if (enmLevel <= pTest->enmMaxLevel)
1061 {
1062 if (!pTest->fNewLine)
1063 cch += rtTestPrintf(pTest, "\n");
1064 cch += rtTestPrintfV(pTest, pszFormat, va);
1065 }
1066
1067 RTCritSectLeave(&pTest->OutputLock);
1068
1069 return cch;
1070}
1071
1072
1073RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
1074{
1075 va_list va;
1076
1077 va_start(va, pszFormat);
1078 int cch = RTTestPrintfNlV(hTest, enmLevel, pszFormat, va);
1079 va_end(va);
1080
1081 return cch;
1082}
1083
1084
1085RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
1086{
1087 PRTTESTINT pTest = hTest;
1088 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1089
1090 RTCritSectEnter(&pTest->OutputLock);
1091 int cch = 0;
1092 if (enmLevel <= pTest->enmMaxLevel)
1093 cch += rtTestPrintfV(pTest, pszFormat, va);
1094 RTCritSectLeave(&pTest->OutputLock);
1095
1096 return cch;
1097}
1098
1099
1100RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
1101{
1102 va_list va;
1103
1104 va_start(va, pszFormat);
1105 int cch = RTTestPrintfV(hTest, enmLevel, pszFormat, va);
1106 va_end(va);
1107
1108 return cch;
1109}
1110
1111
1112RTR3DECL(int) RTTestBanner(RTTEST hTest)
1113{
1114 return RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "TESTING...\n");
1115}
1116
1117
1118/**
1119 * Prints the result of a sub-test if necessary.
1120 *
1121 * @returns Number of chars printed.
1122 * @param pTest The test instance.
1123 * @remarks Caller own the test Lock.
1124 */
1125static int rtTestSubTestReport(PRTTESTINT pTest)
1126{
1127 int cch = 0;
1128 if ( !pTest->fSubTestReported
1129 && pTest->pszSubTest)
1130 {
1131 pTest->fSubTestReported = true;
1132 uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
1133 if (!cErrors)
1134 {
1135 if (!pTest->fSubTestSkipped)
1136 {
1137 rtTestXmlElem(pTest, "Passed", NULL);
1138 rtTestXmlElemEnd(pTest, "Test");
1139 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: PASSED\n", pTest->pszSubTest);
1140 }
1141 else
1142 {
1143 rtTestXmlElem(pTest, "Skipped", NULL);
1144 rtTestXmlElemEnd(pTest, "Test");
1145 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: SKIPPED\n", pTest->pszSubTest);
1146 }
1147 }
1148 else
1149 {
1150 pTest->cSubTestsFailed++;
1151 rtTestXmlElem(pTest, "Failed", "errors=\"%u\"", cErrors);
1152 rtTestXmlElemEnd(pTest, "Test");
1153 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: FAILED (%u errors)\n",
1154 pTest->pszSubTest, cErrors);
1155 }
1156 }
1157 return cch;
1158}
1159
1160
1161/**
1162 * RTTestSub and RTTestSubDone worker that cleans up the current (if any)
1163 * sub test.
1164 *
1165 * @returns Number of chars printed.
1166 * @param pTest The test instance.
1167 * @remarks Caller own the test Lock.
1168 */
1169static int rtTestSubCleanup(PRTTESTINT pTest)
1170{
1171 int cch = 0;
1172 if (pTest->pszSubTest)
1173 {
1174 cch += rtTestSubTestReport(pTest);
1175
1176 RTStrFree((char *)pTest->pszSubTest);
1177 pTest->pszSubTest = NULL;
1178 pTest->fSubTestReported = true;
1179 }
1180 RTStrFree(pTest->pszErrCtx);
1181 pTest->pszErrCtx = NULL;
1182 return cch;
1183}
1184
1185
1186RTR3DECL(RTEXITCODE) RTTestSummaryAndDestroy(RTTEST hTest)
1187{
1188 PRTTESTINT pTest = hTest;
1189 RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_FAILURE);
1190
1191 RTCritSectEnter(&pTest->Lock);
1192 rtTestSubTestReport(pTest);
1193 RTCritSectLeave(&pTest->Lock);
1194
1195 RTEXITCODE enmExitCode;
1196 if (!pTest->cErrors)
1197 {
1198 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SUCCESS\n");
1199 enmExitCode = RTEXITCODE_SUCCESS;
1200 }
1201 else
1202 {
1203 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
1204 enmExitCode = RTEXITCODE_FAILURE;
1205 }
1206
1207 RTTestDestroy(pTest);
1208 return enmExitCode;
1209}
1210
1211
1212RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va)
1213{
1214 PRTTESTINT pTest = hTest;
1215 RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_SKIPPED);
1216
1217 RTCritSectEnter(&pTest->Lock);
1218 rtTestSubTestReport(pTest);
1219 RTCritSectLeave(&pTest->Lock);
1220
1221 RTEXITCODE enmExitCode;
1222 if (!pTest->cErrors)
1223 {
1224 if (pszReasonFmt)
1225 RTTestPrintfNlV(hTest, RTTESTLVL_FAILURE, pszReasonFmt, va);
1226 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SKIPPED\n");
1227 enmExitCode = RTEXITCODE_SKIPPED;
1228 }
1229 else
1230 {
1231 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
1232 enmExitCode = RTEXITCODE_FAILURE;
1233 }
1234
1235 RTTestDestroy(pTest);
1236 return enmExitCode;
1237}
1238
1239
1240RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...)
1241{
1242 va_list va;
1243 va_start(va, pszReasonFmt);
1244 RTEXITCODE enmExitCode = RTTestSkipAndDestroyV(hTest, pszReasonFmt, va);
1245 va_end(va);
1246 return enmExitCode;
1247}
1248
1249
1250RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest)
1251{
1252 PRTTESTINT pTest = hTest;
1253 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1254
1255 RTCritSectEnter(&pTest->Lock);
1256
1257 /* Cleanup, reporting if necessary previous sub test. */
1258 rtTestSubCleanup(pTest);
1259
1260 /* Start new sub test. */
1261 pTest->cSubTests++;
1262 pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors);
1263 pTest->pszSubTest = RTStrDup(pszSubTest);
1264 pTest->cchSubTest = strlen(pszSubTest);
1265 AssertMsg(pTest->cchSubTest < 64 /* See g_kcchMaxTestResultName in testmanager/config.py. */,
1266 ("cchSubTest=%u: '%s'\n", pTest->cchSubTest, pTest->pszSubTest));
1267 pTest->fSubTestSkipped = false;
1268 pTest->fSubTestReported = false;
1269
1270 int cch = 0;
1271 if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
1272 cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
1273
1274 if (!pTest->fXmlTopTestDone)
1275 {
1276 pTest->fXmlTopTestDone = true;
1277 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pTest->pszTest);
1278 }
1279
1280 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszSubTest);
1281
1282 RTCritSectLeave(&pTest->Lock);
1283
1284 return cch;
1285}
1286
1287
1288RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...)
1289{
1290 va_list va;
1291 va_start(va, pszSubTestFmt);
1292 int cch = RTTestSubV(hTest, pszSubTestFmt, va);
1293 va_end(va);
1294 return cch;
1295}
1296
1297
1298RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va)
1299{
1300 char *pszSubTest;
1301 RTStrAPrintfV(&pszSubTest, pszSubTestFmt, va);
1302 if (pszSubTest)
1303 {
1304 int cch = RTTestSub(hTest, pszSubTest);
1305 RTStrFree(pszSubTest);
1306 return cch;
1307 }
1308 return 0;
1309}
1310
1311
1312RTR3DECL(int) RTTestSubDone(RTTEST hTest)
1313{
1314 PRTTESTINT pTest = hTest;
1315 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1316
1317 RTCritSectEnter(&pTest->Lock);
1318 int cch = rtTestSubCleanup(pTest);
1319 RTCritSectLeave(&pTest->Lock);
1320
1321 return cch;
1322}
1323
1324
1325RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
1326{
1327 PRTTESTINT pTest = hTest;
1328 AssertPtr(pszFormat);
1329 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1330
1331 int cch = 0;
1332 if (pTest->enmMaxLevel >= RTTESTLVL_INFO)
1333 {
1334 va_list va2;
1335 va_copy(va2, va);
1336
1337 RTCritSectEnter(&pTest->OutputLock);
1338 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1339 RTCritSectLeave(&pTest->OutputLock);
1340
1341 va_end(va2);
1342 }
1343
1344 return cch;
1345}
1346
1347
1348RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...)
1349{
1350 va_list va;
1351
1352 va_start(va, pszFormat);
1353 int cch = RTTestPassedV(hTest, pszFormat, va);
1354 va_end(va);
1355
1356 return cch;
1357}
1358
1359
1360RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va)
1361{
1362 PRTTESTINT pTest = hTest;
1363 AssertPtrNull(pszFormat);
1364 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1365
1366 pTest->fSubTestSkipped = true;
1367
1368 int cch = 0;
1369 if (pszFormat && *pszFormat && pTest->enmMaxLevel >= RTTESTLVL_INFO)
1370 {
1371 va_list va2;
1372 va_copy(va2, va);
1373
1374 RTCritSectEnter(&pTest->OutputLock);
1375 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1376 RTCritSectLeave(&pTest->OutputLock);
1377
1378 va_end(va2);
1379 }
1380
1381 return cch;
1382}
1383
1384
1385RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...)
1386{
1387 va_list va;
1388
1389 va_start(va, pszFormat);
1390 int cch = RTTestSkippedV(hTest, pszFormat, va);
1391 va_end(va);
1392
1393 return cch;
1394}
1395
1396
1397
1398/**
1399 * Gets the unit name.
1400 *
1401 * @returns Unit name.
1402 * @param enmUnit The unit.
1403 */
1404static const char *rtTestUnitName(RTTESTUNIT enmUnit)
1405{
1406 switch (enmUnit)
1407 {
1408 case RTTESTUNIT_PCT: return "%";
1409 case RTTESTUNIT_BYTES: return "bytes";
1410 case RTTESTUNIT_BYTES_PER_SEC: return "bytes/s";
1411 case RTTESTUNIT_KILOBYTES: return "KB";
1412 case RTTESTUNIT_KILOBYTES_PER_SEC: return "KB/s";
1413 case RTTESTUNIT_MEGABYTES: return "MB";
1414 case RTTESTUNIT_MEGABYTES_PER_SEC: return "MB/s";
1415 case RTTESTUNIT_PACKETS: return "packets";
1416 case RTTESTUNIT_PACKETS_PER_SEC: return "packets/s";
1417 case RTTESTUNIT_FRAMES: return "frames";
1418 case RTTESTUNIT_FRAMES_PER_SEC: return "frames/s";
1419 case RTTESTUNIT_OCCURRENCES: return "occurrences";
1420 case RTTESTUNIT_OCCURRENCES_PER_SEC: return "occurrences/s";
1421 case RTTESTUNIT_ROUND_TRIP: return "roundtrips";
1422 case RTTESTUNIT_CALLS: return "calls";
1423 case RTTESTUNIT_CALLS_PER_SEC: return "calls/s";
1424 case RTTESTUNIT_SECS: return "s";
1425 case RTTESTUNIT_MS: return "ms";
1426 case RTTESTUNIT_NS: return "ns";
1427 case RTTESTUNIT_NS_PER_CALL: return "ns/call";
1428 case RTTESTUNIT_NS_PER_FRAME: return "ns/frame";
1429 case RTTESTUNIT_NS_PER_OCCURRENCE: return "ns/occurrence";
1430 case RTTESTUNIT_NS_PER_PACKET: return "ns/packet";
1431 case RTTESTUNIT_NS_PER_ROUND_TRIP: return "ns/roundtrip";
1432 case RTTESTUNIT_INSTRS: return "ins";
1433 case RTTESTUNIT_INSTRS_PER_SEC: return "ins/sec";
1434 case RTTESTUNIT_NONE: return "";
1435 case RTTESTUNIT_PP1K: return "pp1k";
1436 case RTTESTUNIT_PP10K: return "pp10k";
1437 case RTTESTUNIT_PPM: return "ppm";
1438 case RTTESTUNIT_PPB: return "ppb";
1439 case RTTESTUNIT_TICKS: return "ticks";
1440 case RTTESTUNIT_TICKS_PER_CALL: return "ticks/call";
1441 case RTTESTUNIT_TICKS_PER_OCCURENCE: return "ticks/occ";
1442 case RTTESTUNIT_PAGES: return "pages";
1443 case RTTESTUNIT_PAGES_PER_SEC: return "pages/s";
1444 case RTTESTUNIT_TICKS_PER_PAGE: return "ticks/page";
1445 case RTTESTUNIT_NS_PER_PAGE: return "ns/page";
1446 case RTTESTUNIT_PS: return "ps";
1447 case RTTESTUNIT_PS_PER_CALL: return "ps/call";
1448 case RTTESTUNIT_PS_PER_FRAME: return "ps/frame";
1449 case RTTESTUNIT_PS_PER_OCCURRENCE: return "ps/occurrence";
1450 case RTTESTUNIT_PS_PER_PACKET: return "ps/packet";
1451 case RTTESTUNIT_PS_PER_ROUND_TRIP: return "ps/roundtrip";
1452 case RTTESTUNIT_PS_PER_PAGE: return "ps/page";
1453
1454 /* No default so gcc helps us keep this up to date. */
1455 case RTTESTUNIT_INVALID:
1456 case RTTESTUNIT_END:
1457 break;
1458 }
1459 AssertMsgFailed(("%d\n", enmUnit));
1460 return "unknown";
1461}
1462
1463
1464RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit)
1465{
1466 PRTTESTINT pTest = hTest;
1467 RTTEST_GET_VALID_RETURN(pTest);
1468
1469 Assert(strlen(pszName) < 56 /* See g_kcchMaxTestValueName in testmanager/config.py. */);
1470
1471 const char *pszUnit = rtTestUnitName(enmUnit);
1472
1473 RTCritSectEnter(&pTest->Lock);
1474 rtTestXmlElem(pTest, "Value", "name=%RMas unit=%RMas value=\"%llu\"", pszName, pszUnit, u64Value);
1475 RTCritSectLeave(&pTest->Lock);
1476
1477 RTCritSectEnter(&pTest->OutputLock);
1478 rtTestPrintf(pTest, " %-58s: %'16llu %s\n", pszName, u64Value, pszUnit);
1479 RTCritSectLeave(&pTest->OutputLock);
1480
1481 return VINF_SUCCESS;
1482}
1483
1484
1485RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...)
1486{
1487 va_list va;
1488 va_start(va, pszNameFmt);
1489 int rc = RTTestValueV(hTest, u64Value, enmUnit, pszNameFmt, va);
1490 va_end(va);
1491 return rc;
1492}
1493
1494
1495RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va)
1496{
1497 char *pszName;
1498 RTStrAPrintfV(&pszName, pszNameFmt, va);
1499 if (!pszName)
1500 return VERR_NO_MEMORY;
1501 int rc = RTTestValue(hTest, pszName, u64Value, enmUnit);
1502 RTStrFree(pszName);
1503 return rc;
1504}
1505
1506
1507RTR3DECL(int) RTTestErrorInc(RTTEST hTest)
1508{
1509 PRTTESTINT pTest = hTest;
1510 RTTEST_GET_VALID_RETURN(pTest);
1511
1512 ASMAtomicIncU32(&pTest->cErrors);
1513
1514 return VINF_SUCCESS;
1515}
1516
1517
1518RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest)
1519{
1520 PRTTESTINT pTest = hTest;
1521 RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
1522
1523 return ASMAtomicReadU32(&pTest->cErrors);
1524}
1525
1526
1527RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest)
1528{
1529 PRTTESTINT pTest = hTest;
1530 RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
1531
1532 return ASMAtomicReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
1533}
1534
1535
1536RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va)
1537{
1538 PRTTESTINT pTest = hTest;
1539 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1540
1541 RTTestErrorInc(pTest);
1542
1543 int cch = 0;
1544 if (pTest->enmMaxLevel >= RTTESTLVL_FAILURE)
1545 {
1546 va_list va2;
1547 va_copy(va2, va);
1548
1549 const char *pszEnd = strchr(pszFormat, '\0');
1550 bool fHasNewLine = pszFormat != pszEnd
1551 && pszEnd[-1] == '\n';
1552
1553 RTCritSectEnter(&pTest->OutputLock);
1554 cch += rtTestPrintf(pTest, fHasNewLine ? "%N" : "%N\n", pszFormat, &va2);
1555 if (pTest->pszErrCtx)
1556 {
1557 cch += rtTestPrintf(pTest, "context: %s\n", pTest->pszErrCtx);
1558 RTStrFree(pTest->pszErrCtx);
1559 pTest->pszErrCtx = NULL;
1560 }
1561 RTCritSectLeave(&pTest->OutputLock);
1562
1563 va_end(va2);
1564 }
1565
1566 return cch;
1567}
1568
1569
1570RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...)
1571{
1572 va_list va;
1573
1574 va_start(va, pszFormat);
1575 int cch = RTTestFailedV(hTest, pszFormat, va);
1576 va_end(va);
1577
1578 return cch;
1579}
1580
1581
1582RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va)
1583{
1584 return RTTestPrintfV(hTest, RTTESTLVL_FAILURE, pszFormat, va);
1585}
1586
1587
1588RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...)
1589{
1590 va_list va;
1591 va_start(va, pszFormat);
1592 int cch = RTTestFailureDetailsV(hTest, pszFormat, va);
1593 va_end(va);
1594 return cch;
1595}
1596
1597
1598RTR3DECL(int) RTTestErrContextV(RTTEST hTest, const char *pszFormat, va_list va)
1599{
1600 PRTTESTINT pTest = hTest;
1601 RTTEST_GET_VALID_RETURN(pTest);
1602
1603 RTStrFree(pTest->pszErrCtx);
1604 pTest->pszErrCtx = NULL;
1605
1606 if (pszFormat && *pszFormat)
1607 {
1608 pTest->pszErrCtx = RTStrAPrintf2V(pszFormat, va);
1609 AssertReturn(pTest->pszErrCtx, VERR_NO_STR_MEMORY);
1610 RTStrStripR(pTest->pszErrCtx);
1611 }
1612
1613 return VINF_SUCCESS;
1614}
1615
1616
1617RTR3DECL(int) RTTestErrContext(RTTEST hTest, const char *pszFormat, ...)
1618{
1619 va_list va;
1620 va_start(va, pszFormat);
1621 int rc = RTTestErrContextV(hTest, pszFormat, va);
1622 va_end(va);
1623 return rc;
1624}
1625
1626
1627RTR3DECL(int) RTTestDisableAssertions(RTTEST hTest)
1628{
1629 PRTTESTINT pTest = hTest;
1630 RTTEST_GET_VALID_RETURN(pTest);
1631
1632 uint32_t cTimes = ASMAtomicIncU32(&pTest->cAssertionsDisabledAndQuieted);
1633 if (cTimes >= 2 && cTimes <= 8)
1634 return VINF_SUCCESS;
1635 if (cTimes > 8)
1636 {
1637 RTAssertSetMayPanic(pTest->fAssertSavedMayPanic);
1638 RTAssertSetQuiet(pTest->fAssertSavedQuiet);
1639 Assert(cTimes <= 8);
1640 }
1641 pTest->fAssertSavedMayPanic = RTAssertSetMayPanic(false);
1642 pTest->fAssertSavedQuiet = RTAssertSetQuiet(true);
1643 return VINF_SUCCESS;
1644}
1645
1646
1647RTR3DECL(int) RTTestRestoreAssertions(RTTEST hTest)
1648{
1649 PRTTESTINT pTest = hTest;
1650 RTTEST_GET_VALID_RETURN(pTest);
1651
1652 uint32_t cTimes = ASMAtomicDecU32(&pTest->cAssertionsDisabledAndQuieted);
1653 if (cTimes == 0)
1654 {
1655 RTAssertSetMayPanic(pTest->fAssertSavedMayPanic);
1656 RTAssertSetQuiet(pTest->fAssertSavedQuiet);
1657 }
1658 else
1659 AssertStmt(cTimes < UINT32_MAX / 2, ASMAtomicIncU32(&pTest->cAssertionsDisabledAndQuieted));
1660 return VINF_SUCCESS;
1661}
1662
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