VirtualBox

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

Last change on this file since 96781 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.7 KB
Line 
1/* $Id: test.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Testcase Framework.
4 */
5
6/*
7 * Copyright (C) 2009-2022 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
488/**
489 * Destroys a test instance previously created by RTTestCreate.
490 *
491 * @returns IPRT status code.
492 * @param hTest The test handle. NIL_RTTEST is ignored.
493 */
494RTR3DECL(int) RTTestDestroy(RTTEST hTest)
495{
496 /*
497 * Validate
498 */
499 if (hTest == NIL_RTTEST)
500 return VINF_SUCCESS;
501 RTTESTINT *pTest = hTest;
502 RTTEST_VALID_RETURN(pTest);
503
504 /*
505 * Make sure we end with a new line and have finished up the XML.
506 */
507 if (!pTest->fNewLine)
508 rtTestPrintf(pTest, "\n");
509 rtTestXmlEnd(pTest);
510
511 /*
512 * Clean up.
513 */
514 if ((RTTESTINT *)RTTlsGet(g_iTestTls) == pTest)
515 RTTlsSet(g_iTestTls, NULL);
516
517 ASMAtomicWriteU32(&pTest->u32Magic, ~RTTESTINT_MAGIC);
518 RTCritSectDelete(&pTest->Lock);
519 RTCritSectDelete(&pTest->OutputLock);
520
521 /* free guarded memory. */
522 PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem;
523 pTest->pGuardedMem = NULL;
524 while (pMem)
525 {
526 PRTTESTGUARDEDMEM pFree = pMem;
527 pMem = pMem->pNext;
528 rtTestGuardedFreeOne(pFree);
529 }
530
531 RTStrFree((char *)pTest->pszSubTest);
532 pTest->pszSubTest = NULL;
533 RTStrFree((char *)pTest->pszTest);
534 pTest->pszTest = NULL;
535 RTStrFree(pTest->pszErrCtx);
536 pTest->pszErrCtx = NULL;
537 RTMemFree(pTest);
538 return VINF_SUCCESS;
539}
540
541
542/**
543 * Changes the default test instance for the calling thread.
544 *
545 * @returns IPRT status code.
546 *
547 * @param hNewDefaultTest The new default test. NIL_RTTEST is fine.
548 * @param phOldTest Where to store the old test handle. Optional.
549 */
550RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest)
551{
552 if (phOldTest)
553 *phOldTest = (RTTEST)RTTlsGet(g_iTestTls);
554 return RTTlsSet(g_iTestTls, hNewDefaultTest);
555}
556
557
558RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName)
559{
560 PRTTESTINT pTest = hTest;
561 RTTEST_GET_VALID_RETURN(pTest);
562 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
563 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
564
565 size_t cchName = strlen(pszName);
566 AssertReturn(cchName < 128, VERR_INVALID_PARAMETER);
567 char *pszDupName = RTStrDup(pszName);
568 if (!pszDupName)
569 return VERR_NO_STR_MEMORY;
570
571 RTCritSectEnter(&pTest->Lock);
572 RTCritSectEnter(&pTest->OutputLock);
573
574 char *pszOldName = (char *)pTest->pszTest;
575 pTest->pszTest = pszDupName;
576 pTest->cchTest = cchName;
577
578 RTCritSectLeave(&pTest->OutputLock);
579 RTCritSectLeave(&pTest->Lock);
580
581 RTStrFree(pszOldName);
582 return VINF_SUCCESS;
583}
584
585
586/**
587 * Allocate a block of guarded memory.
588 *
589 * @returns IPRT status code.
590 * @param hTest The test handle. If NIL_RTTEST we'll use the one
591 * associated with the calling thread.
592 * @param cb The amount of memory to allocate.
593 * @param cbAlign The alignment of the returned block.
594 * @param fHead Head or tail optimized guard.
595 * @param ppvUser Where to return the pointer to the block.
596 */
597RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser)
598{
599 PRTTESTINT pTest = hTest;
600 RTTEST_GET_VALID_RETURN(pTest);
601 if (cbAlign == 0)
602 cbAlign = 1;
603 AssertReturn(cbAlign <= PAGE_SIZE, VERR_INVALID_PARAMETER);
604 AssertReturn(cbAlign == (UINT32_C(1) << (ASMBitFirstSetU32(cbAlign) - 1)), VERR_INVALID_PARAMETER);
605
606 /*
607 * Allocate the record and block and initialize them.
608 */
609 int rc = VERR_NO_MEMORY;
610 PRTTESTGUARDEDMEM pMem = (PRTTESTGUARDEDMEM)RTMemAlloc(sizeof(*pMem));
611 if (RT_LIKELY(pMem))
612 {
613 size_t const cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
614 pMem->aGuards[0].cb = pMem->aGuards[1].cb = pTest->cbGuard;
615 pMem->cbAlloc = pMem->aGuards[0].cb + pMem->aGuards[1].cb + cbAligned;
616 pMem->pvAlloc = RTMemPageAlloc(pMem->cbAlloc);
617 if (pMem->pvAlloc)
618 {
619 pMem->aGuards[0].pv = pMem->pvAlloc;
620 pMem->pvUser = (uint8_t *)pMem->pvAlloc + pMem->aGuards[0].cb;
621 pMem->aGuards[1].pv = (uint8_t *)pMem->pvUser + cbAligned;
622 if (!fHead)
623 {
624 size_t off = cb & PAGE_OFFSET_MASK;
625 if (off)
626 {
627 off = PAGE_SIZE - RT_ALIGN_Z(off, cbAlign);
628 pMem->pvUser = (uint8_t *)pMem->pvUser + off;
629 }
630 }
631
632 /*
633 * Set up the guards and link the record.
634 */
635 ASMMemFill32(pMem->aGuards[0].pv, pMem->aGuards[0].cb, 0xdeadbeef);
636 ASMMemFill32(pMem->aGuards[1].pv, pMem->aGuards[1].cb, 0xdeadbeef);
637 rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_NONE);
638 if (RT_SUCCESS(rc))
639 {
640 rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_NONE);
641 if (RT_SUCCESS(rc))
642 {
643 *ppvUser = pMem->pvUser;
644
645 RTCritSectEnter(&pTest->Lock);
646 pMem->pNext = pTest->pGuardedMem;
647 pTest->pGuardedMem = pMem;
648 RTCritSectLeave(&pTest->Lock);
649
650 return VINF_SUCCESS;
651 }
652
653 RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ);
654 }
655
656 RTMemPageFree(pMem->pvAlloc, pMem->cbAlloc);
657 }
658 RTMemFree(pMem);
659 }
660 return rc;
661}
662
663
664/**
665 * Allocates a block of guarded memory where the guarded is immediately after
666 * the user memory.
667 *
668 * @returns Pointer to the allocated memory. NULL on failure.
669 * @param hTest The test handle. If NIL_RTTEST we'll use the one
670 * associated with the calling thread.
671 * @param cb The amount of memory to allocate.
672 */
673RTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb)
674{
675 void *pvUser;
676 int rc = RTTestGuardedAlloc(hTest, cb, 1 /* cbAlign */, false /* fHead */, &pvUser);
677 if (RT_SUCCESS(rc))
678 return pvUser;
679 return NULL;
680}
681
682
683/**
684 * Allocates a block of guarded memory where the guarded is right in front of
685 * the user memory.
686 *
687 * @returns Pointer to the allocated memory. NULL on failure.
688 * @param hTest The test handle. If NIL_RTTEST we'll use the one
689 * associated with the calling thread.
690 * @param cb The amount of memory to allocate.
691 */
692RTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb)
693{
694 void *pvUser;
695 int rc = RTTestGuardedAlloc(hTest, cb, 1 /* cbAlign */, true /* fHead */, &pvUser);
696 if (RT_SUCCESS(rc))
697 return pvUser;
698 return NULL;
699}
700
701
702/**
703 * Frees one block of guarded memory.
704 *
705 * The caller is responsible for unlinking it.
706 *
707 * @param pMem The memory record.
708 */
709static void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem)
710{
711 int rc;
712 rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
713 rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
714 RTMemPageFree(pMem->pvAlloc, pMem->cbAlloc);
715 RTMemFree(pMem);
716}
717
718
719/**
720 * Frees a block of guarded memory.
721 *
722 * @returns IPRT status code.
723 * @param hTest The test handle. If NIL_RTTEST we'll use the one
724 * associated with the calling thread.
725 * @param pv The memory. NULL is ignored.
726 */
727RTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv)
728{
729 PRTTESTINT pTest = hTest;
730 RTTEST_GET_VALID_RETURN(pTest);
731 if (!pv)
732 return VINF_SUCCESS;
733
734 /*
735 * Find it.
736 */
737 int rc = VERR_INVALID_POINTER;
738 PRTTESTGUARDEDMEM pPrev = NULL;
739
740 RTCritSectEnter(&pTest->Lock);
741 for (PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem; pMem; pMem = pMem->pNext)
742 {
743 if (pMem->pvUser == pv)
744 {
745 if (pPrev)
746 pPrev->pNext = pMem->pNext;
747 else
748 pTest->pGuardedMem = pMem->pNext;
749 rtTestGuardedFreeOne(pMem);
750 rc = VINF_SUCCESS;
751 break;
752 }
753 pPrev = pMem;
754 }
755 RTCritSectLeave(&pTest->Lock);
756
757 return rc;
758}
759
760
761/**
762 * Outputs the formatted XML.
763 *
764 * @param pTest The test instance.
765 * @param pszFormat The format string.
766 * @param va The format arguments.
767 */
768static void rtTestXmlOutputV(PRTTESTINT pTest, const char *pszFormat, va_list va)
769{
770 if (pTest->fXmlEnabled)
771 {
772 char *pszStr;
773 ssize_t cchStr = RTStrAPrintfV(&pszStr, pszFormat, va);
774 if (pszStr)
775 {
776 if (pTest->hXmlPipe != NIL_RTPIPE)
777 RTPipeWriteBlocking(pTest->hXmlPipe, pszStr, cchStr, NULL);
778 if (pTest->hXmlFile != NIL_RTFILE)
779 RTFileWrite(pTest->hXmlFile, pszStr, cchStr, NULL);
780 RTStrFree(pszStr);
781 }
782 }
783}
784
785
786/**
787 * Outputs the formatted XML.
788 *
789 * @param pTest The test instance.
790 * @param pszFormat The format string.
791 * @param ... The format arguments.
792 */
793static void rtTestXmlOutput(PRTTESTINT pTest, const char *pszFormat, ...)
794{
795 va_list va;
796 va_start(va, pszFormat);
797 rtTestXmlOutputV(pTest, pszFormat, va);
798 va_end(va);
799}
800
801
802/**
803 * Starts the XML stream.
804 *
805 * @param pTest The test instance.
806 * @param pszTest The test name.
807 */
808static void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest)
809{
810 pTest->cXmlElements = 0;
811 if (pTest->fXmlEnabled)
812 {
813 rtTestXmlOutput(pTest, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
814 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
815 pTest->fXmlTopTestDone = !(pTest->fFlags & RTTEST_C_XML_DELAY_TOP_TEST) || pTest->fXmlOmitTopTest;
816 if (pTest->fXmlTopTestDone && !pTest->fXmlOmitTopTest)
817 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest);
818 }
819}
820
821
822/**
823 * Emit an XML element that doesn't have any value and instead ends immediately.
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 rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
834{
835 if (pTest->fXmlEnabled)
836 {
837 RTTIMESPEC TimeSpec;
838 RTTIME Time;
839 char szTS[80];
840 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
841
842 if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
843 rtTestXmlOutput(pTest, "\n");
844
845 if (!pszAttrFmt || !*pszAttrFmt)
846 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas/>\n",
847 pTest->cXmlElements * 2, "", pszTag, szTS);
848 else
849 {
850 va_list va2;
851 va_copy(va2, va);
852 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N/>\n",
853 pTest->cXmlElements * 2, "", pszTag, szTS, pszAttrFmt, &va2);
854 va_end(va2);
855 }
856 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
857 }
858}
859
860
861/**
862 * Wrapper around rtTestXmlElemV.
863 */
864static void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
865{
866 va_list va;
867 va_start(va, pszAttrFmt);
868 rtTestXmlElemV(pTest, pszTag, pszAttrFmt, va);
869 va_end(va);
870}
871
872
873/**
874 * Starts a new XML element.
875 *
876 * The caller must own the instance lock.
877 *
878 * @param pTest The test instance.
879 * @param pszTag The element tag.
880 * @param pszAttrFmt The element attributes as a format string. Use
881 * NULL if none.
882 * @param va Format string arguments.
883 */
884static void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
885{
886 /* Push it onto the stack. */
887 size_t i = pTest->cXmlElements;
888 AssertReturnVoid(i < RT_ELEMENTS(pTest->apszXmlElements));
889 pTest->apszXmlElements[i] = pszTag;
890 pTest->cXmlElements = i + 1;
891
892 if (pTest->fXmlEnabled)
893 {
894 RTTIMESPEC TimeSpec;
895 RTTIME Time;
896 char szTS[80];
897 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
898
899 if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
900 rtTestXmlOutput(pTest, "\n");
901
902 if (!pszAttrFmt || !*pszAttrFmt)
903 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas>",
904 i * 2, "", pszTag, szTS);
905 else
906 {
907 va_list va2;
908 va_copy(va2, va);
909 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N>",
910 i * 2, "", pszTag, szTS, pszAttrFmt, &va2);
911 va_end(va2);
912 }
913 pTest->eXmlState = RTTESTINT::kXmlPos_ValueStart;
914 }
915}
916
917
918/**
919 * Wrapper around rtTestXmlElemStartV.
920 */
921static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
922{
923 va_list va;
924 va_start(va, pszAttrFmt);
925 rtTestXmlElemStartV(pTest, pszTag, pszAttrFmt, va);
926 va_end(va);
927}
928
929
930/**
931 * Ends the current element.
932 *
933 * The caller must own the instance lock.
934 *
935 * @param pTest The test instance.
936 * @param pszTag The tag we're ending (chiefly for sanity
937 * checking).
938 */
939static void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag)
940{
941 /* pop the element */
942 size_t i = pTest->cXmlElements;
943 AssertReturnVoid(i > 0);
944 i--;
945 AssertReturnVoid(!strcmp(pszTag, pTest->apszXmlElements[i]));
946 pTest->cXmlElements = i;
947
948 /* Do the closing. */
949 if (pTest->fXmlEnabled)
950 {
951 if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
952 rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
953 else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
954 rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
955 else
956 rtTestXmlOutput(pTest, "</%s>\n", pszTag);
957 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
958 }
959}
960
961
962/**
963 * Ends the XML stream, closing all open elements.
964 *
965 * The caller must own the instance lock.
966 *
967 * @param pTest The test instance.
968 */
969static void rtTestXmlEnd(PRTTESTINT pTest)
970{
971 if (pTest->fXmlEnabled)
972 {
973 /*
974 * Close all the elements and add the final TestEnd one to get a
975 * final timestamp and some certainty that the XML is valid.
976 */
977 size_t i = pTest->cXmlElements;
978 AssertReturnVoid(i > 0 || pTest->fXmlOmitTopTest || !pTest->fXmlTopTestDone);
979 while (i-- > 1)
980 {
981 const char *pszTag = pTest->apszXmlElements[pTest->cXmlElements];
982 if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
983 rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
984 else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
985 rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
986 else
987 rtTestXmlOutput(pTest, "</%s>\n", pszTag);
988 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
989 }
990
991 if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone)
992 {
993 rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"",
994 pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors);
995 rtTestXmlOutput(pTest, "</Test>\n");
996 }
997
998 /*
999 * Close the XML outputs.
1000 */
1001 if (pTest->hXmlPipe != NIL_RTPIPE)
1002 {
1003 RTPipeClose(pTest->hXmlPipe);
1004 pTest->hXmlPipe = NIL_RTPIPE;
1005 }
1006 if (pTest->hXmlFile != NIL_RTFILE)
1007 {
1008 RTFileClose(pTest->hXmlFile);
1009 pTest->hXmlFile = NIL_RTFILE;
1010 }
1011 pTest->fXmlEnabled = false;
1012 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
1013 }
1014 pTest->cXmlElements = 0;
1015}
1016
1017/**
1018 * Output callback.
1019 *
1020 * @returns number of bytes written.
1021 * @param pvArg User argument.
1022 * @param pachChars Pointer to an array of utf-8 characters.
1023 * @param cbChars Number of bytes in the character array pointed to by pachChars.
1024 */
1025static DECLCALLBACK(size_t) rtTestPrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
1026{
1027 size_t cch = 0;
1028 PRTTESTINT pTest = (PRTTESTINT)pvArg;
1029 if (cbChars)
1030 {
1031 do
1032 {
1033 /* insert prefix if at a newline. */
1034 if (pTest->fNewLine)
1035 {
1036 RTStrmWrite(pTest->pOutStrm, pTest->pszTest, pTest->cchTest);
1037 RTStrmWrite(pTest->pOutStrm, ": ", 2);
1038 cch += 2 + pTest->cchTest;
1039 }
1040
1041 /* look for newline and write the stuff. */
1042 const char *pchEnd = (const char *)memchr(pachChars, '\n', cbChars);
1043 if (!pchEnd)
1044 {
1045 pTest->fNewLine = false;
1046 RTStrmWrite(pTest->pOutStrm, pachChars, cbChars);
1047 cch += cbChars;
1048 break;
1049 }
1050
1051 pTest->fNewLine = true;
1052 size_t const cchPart = pchEnd - pachChars + 1;
1053 RTStrmWrite(pTest->pOutStrm, pachChars, cchPart);
1054 cch += cchPart;
1055 pachChars += cchPart;
1056 cbChars -= cchPart;
1057 } while (cbChars);
1058 }
1059 else
1060 RTStrmFlush(pTest->pOutStrm);
1061 return cch;
1062}
1063
1064
1065/**
1066 * Internal output worker.
1067 *
1068 * Caller takes the lock.
1069 *
1070 * @returns Number of chars printed.
1071 * @param pTest The test instance.
1072 * @param pszFormat The message.
1073 * @param va The arguments.
1074 */
1075static int rtTestPrintfV(PRTTESTINT pTest, const char *pszFormat, va_list va)
1076{
1077 return (int)RTStrFormatV(rtTestPrintfOutput, pTest, NULL, NULL, pszFormat, va);
1078}
1079
1080
1081/**
1082 * Internal output worker.
1083 *
1084 * Caller takes the lock.
1085 *
1086 * @returns Number of chars printed.
1087 * @param pTest The test instance.
1088 * @param pszFormat The message.
1089 * @param ... The arguments.
1090 */
1091static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...)
1092{
1093 va_list va;
1094
1095 va_start(va, pszFormat);
1096 int cch = rtTestPrintfV(pTest, pszFormat, va);
1097 va_end(va);
1098
1099 return cch;
1100}
1101
1102
1103/**
1104 * Test vprintf making sure the output starts on a new line.
1105 *
1106 * @returns Number of chars printed.
1107 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1108 * associated with the calling thread.
1109 * @param enmLevel Message importance level.
1110 * @param pszFormat The message.
1111 * @param va Arguments.
1112 */
1113RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
1114{
1115 PRTTESTINT pTest = hTest;
1116 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1117
1118 RTCritSectEnter(&pTest->OutputLock);
1119
1120 int cch = 0;
1121 if (enmLevel <= pTest->enmMaxLevel)
1122 {
1123 if (!pTest->fNewLine)
1124 cch += rtTestPrintf(pTest, "\n");
1125 cch += rtTestPrintfV(pTest, pszFormat, va);
1126 }
1127
1128 RTCritSectLeave(&pTest->OutputLock);
1129
1130 return cch;
1131}
1132
1133
1134/**
1135 * Test printf making sure the output starts on a new line.
1136 *
1137 * @returns Number of chars printed.
1138 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1139 * associated with the calling thread.
1140 * @param enmLevel Message importance level.
1141 * @param pszFormat The message.
1142 * @param ... Arguments.
1143 */
1144RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
1145{
1146 va_list va;
1147
1148 va_start(va, pszFormat);
1149 int cch = RTTestPrintfNlV(hTest, enmLevel, pszFormat, va);
1150 va_end(va);
1151
1152 return cch;
1153}
1154
1155
1156/**
1157 * Test vprintf, makes sure lines are prefixed and so forth.
1158 *
1159 * @returns Number of chars printed.
1160 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1161 * associated with the calling thread.
1162 * @param enmLevel Message importance level.
1163 * @param pszFormat The message.
1164 * @param va Arguments.
1165 */
1166RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
1167{
1168 PRTTESTINT pTest = hTest;
1169 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1170
1171 RTCritSectEnter(&pTest->OutputLock);
1172 int cch = 0;
1173 if (enmLevel <= pTest->enmMaxLevel)
1174 cch += rtTestPrintfV(pTest, pszFormat, va);
1175 RTCritSectLeave(&pTest->OutputLock);
1176
1177 return cch;
1178}
1179
1180
1181/**
1182 * Test printf, makes sure lines are prefixed and so forth.
1183 *
1184 * @returns Number of chars printed.
1185 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1186 * associated with the calling thread.
1187 * @param enmLevel Message importance level.
1188 * @param pszFormat The message.
1189 * @param ... Arguments.
1190 */
1191RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
1192{
1193 va_list va;
1194
1195 va_start(va, pszFormat);
1196 int cch = RTTestPrintfV(hTest, enmLevel, pszFormat, va);
1197 va_end(va);
1198
1199 return cch;
1200}
1201
1202
1203/**
1204 * Prints the test banner.
1205 *
1206 * @returns Number of chars printed.
1207 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1208 * associated with the calling thread.
1209 */
1210RTR3DECL(int) RTTestBanner(RTTEST hTest)
1211{
1212 return RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "TESTING...\n");
1213}
1214
1215
1216/**
1217 * Prints the result of a sub-test if necessary.
1218 *
1219 * @returns Number of chars printed.
1220 * @param pTest The test instance.
1221 * @remarks Caller own the test Lock.
1222 */
1223static int rtTestSubTestReport(PRTTESTINT pTest)
1224{
1225 int cch = 0;
1226 if ( !pTest->fSubTestReported
1227 && pTest->pszSubTest)
1228 {
1229 pTest->fSubTestReported = true;
1230 uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
1231 if (!cErrors)
1232 {
1233 if (!pTest->fSubTestSkipped)
1234 {
1235 rtTestXmlElem(pTest, "Passed", NULL);
1236 rtTestXmlElemEnd(pTest, "Test");
1237 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: PASSED\n", pTest->pszSubTest);
1238 }
1239 else
1240 {
1241 rtTestXmlElem(pTest, "Skipped", NULL);
1242 rtTestXmlElemEnd(pTest, "Test");
1243 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: SKIPPED\n", pTest->pszSubTest);
1244 }
1245 }
1246 else
1247 {
1248 pTest->cSubTestsFailed++;
1249 rtTestXmlElem(pTest, "Failed", "errors=\"%u\"", cErrors);
1250 rtTestXmlElemEnd(pTest, "Test");
1251 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: FAILED (%u errors)\n",
1252 pTest->pszSubTest, cErrors);
1253 }
1254 }
1255 return cch;
1256}
1257
1258
1259/**
1260 * RTTestSub and RTTestSubDone worker that cleans up the current (if any)
1261 * sub test.
1262 *
1263 * @returns Number of chars printed.
1264 * @param pTest The test instance.
1265 * @remarks Caller own the test Lock.
1266 */
1267static int rtTestSubCleanup(PRTTESTINT pTest)
1268{
1269 int cch = 0;
1270 if (pTest->pszSubTest)
1271 {
1272 cch += rtTestSubTestReport(pTest);
1273
1274 RTStrFree((char *)pTest->pszSubTest);
1275 pTest->pszSubTest = NULL;
1276 pTest->fSubTestReported = true;
1277 }
1278 RTStrFree(pTest->pszErrCtx);
1279 pTest->pszErrCtx = NULL;
1280 return cch;
1281}
1282
1283
1284/**
1285 * Summaries the test, destroys the test instance and return an exit code.
1286 *
1287 * @returns Test program exit code.
1288 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1289 * associated with the calling thread.
1290 */
1291RTR3DECL(RTEXITCODE) RTTestSummaryAndDestroy(RTTEST hTest)
1292{
1293 PRTTESTINT pTest = hTest;
1294 RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_FAILURE);
1295
1296 RTCritSectEnter(&pTest->Lock);
1297 rtTestSubTestReport(pTest);
1298 RTCritSectLeave(&pTest->Lock);
1299
1300 RTEXITCODE enmExitCode;
1301 if (!pTest->cErrors)
1302 {
1303 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SUCCESS\n");
1304 enmExitCode = RTEXITCODE_SUCCESS;
1305 }
1306 else
1307 {
1308 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
1309 enmExitCode = RTEXITCODE_FAILURE;
1310 }
1311
1312 RTTestDestroy(pTest);
1313 return enmExitCode;
1314}
1315
1316
1317RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va)
1318{
1319 PRTTESTINT pTest = hTest;
1320 RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_SKIPPED);
1321
1322 RTCritSectEnter(&pTest->Lock);
1323 rtTestSubTestReport(pTest);
1324 RTCritSectLeave(&pTest->Lock);
1325
1326 RTEXITCODE enmExitCode;
1327 if (!pTest->cErrors)
1328 {
1329 if (pszReasonFmt)
1330 RTTestPrintfNlV(hTest, RTTESTLVL_FAILURE, pszReasonFmt, va);
1331 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SKIPPED\n");
1332 enmExitCode = RTEXITCODE_SKIPPED;
1333 }
1334 else
1335 {
1336 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
1337 enmExitCode = RTEXITCODE_FAILURE;
1338 }
1339
1340 RTTestDestroy(pTest);
1341 return enmExitCode;
1342}
1343
1344
1345RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...)
1346{
1347 va_list va;
1348 va_start(va, pszReasonFmt);
1349 RTEXITCODE enmExitCode = RTTestSkipAndDestroyV(hTest, pszReasonFmt, va);
1350 va_end(va);
1351 return enmExitCode;
1352}
1353
1354
1355/**
1356 * Starts a sub-test.
1357 *
1358 * This will perform an implicit RTTestSubDone() call if that has not been done
1359 * since the last RTTestSub call.
1360 *
1361 * @returns Number of chars printed.
1362 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1363 * associated with the calling thread.
1364 * @param pszSubTest The sub-test name
1365 */
1366RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest)
1367{
1368 PRTTESTINT pTest = hTest;
1369 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1370
1371 RTCritSectEnter(&pTest->Lock);
1372
1373 /* Cleanup, reporting if necessary previous sub test. */
1374 rtTestSubCleanup(pTest);
1375
1376 /* Start new sub test. */
1377 pTest->cSubTests++;
1378 pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors);
1379 pTest->pszSubTest = RTStrDup(pszSubTest);
1380 pTest->cchSubTest = strlen(pszSubTest);
1381 Assert(pTest->cchSubTest < 64 /* See g_kcchMaxTestResultName in testmanager/config.py. */);
1382 pTest->fSubTestSkipped = false;
1383 pTest->fSubTestReported = false;
1384
1385 int cch = 0;
1386 if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
1387 cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
1388
1389 if (!pTest->fXmlTopTestDone)
1390 {
1391 pTest->fXmlTopTestDone = true;
1392 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pTest->pszTest);
1393 }
1394
1395 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszSubTest);
1396
1397 RTCritSectLeave(&pTest->Lock);
1398
1399 return cch;
1400}
1401
1402
1403/**
1404 * Format string version of RTTestSub.
1405 *
1406 * See RTTestSub for details.
1407 *
1408 * @returns Number of chars printed.
1409 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1410 * associated with the calling thread.
1411 * @param pszSubTestFmt The sub-test name format string.
1412 * @param ... Arguments.
1413 */
1414RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...)
1415{
1416 va_list va;
1417 va_start(va, pszSubTestFmt);
1418 int cch = RTTestSubV(hTest, pszSubTestFmt, va);
1419 va_end(va);
1420 return cch;
1421}
1422
1423
1424/**
1425 * Format string version of RTTestSub.
1426 *
1427 * See RTTestSub for details.
1428 *
1429 * @returns Number of chars printed.
1430 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1431 * associated with the calling thread.
1432 * @param pszSubTestFmt The sub-test name format string.
1433 * @param ... Arguments.
1434 */
1435RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va)
1436{
1437 char *pszSubTest;
1438 RTStrAPrintfV(&pszSubTest, pszSubTestFmt, va);
1439 if (pszSubTest)
1440 {
1441 int cch = RTTestSub(hTest, pszSubTest);
1442 RTStrFree(pszSubTest);
1443 return cch;
1444 }
1445 return 0;
1446}
1447
1448
1449/**
1450 * Completes a sub-test.
1451 *
1452 * @returns Number of chars printed.
1453 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1454 * associated with the calling thread.
1455 */
1456RTR3DECL(int) RTTestSubDone(RTTEST hTest)
1457{
1458 PRTTESTINT pTest = hTest;
1459 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1460
1461 RTCritSectEnter(&pTest->Lock);
1462 int cch = rtTestSubCleanup(pTest);
1463 RTCritSectLeave(&pTest->Lock);
1464
1465 return cch;
1466}
1467
1468/**
1469 * Prints an extended PASSED message, optional.
1470 *
1471 * This does not conclude the sub-test, it could be used to report the passing
1472 * of a sub-sub-to-the-power-of-N-test.
1473 *
1474 * @returns IPRT status code.
1475 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1476 * associated with the calling thread.
1477 * @param pszFormat The message. No trailing newline.
1478 * @param va The arguments.
1479 */
1480RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
1481{
1482 PRTTESTINT pTest = hTest;
1483 AssertPtr(pszFormat);
1484 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1485
1486 int cch = 0;
1487 if (pTest->enmMaxLevel >= RTTESTLVL_INFO)
1488 {
1489 va_list va2;
1490 va_copy(va2, va);
1491
1492 RTCritSectEnter(&pTest->OutputLock);
1493 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1494 RTCritSectLeave(&pTest->OutputLock);
1495
1496 va_end(va2);
1497 }
1498
1499 return cch;
1500}
1501
1502
1503/**
1504 * Prints an extended PASSED message, optional.
1505 *
1506 * This does not conclude the sub-test, it could be used to report the passing
1507 * of a sub-sub-to-the-power-of-N-test.
1508 *
1509 * @returns IPRT status code.
1510 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1511 * associated with the calling thread.
1512 * @param pszFormat The message. No trailing newline.
1513 * @param ... The arguments.
1514 */
1515RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...)
1516{
1517 va_list va;
1518
1519 va_start(va, pszFormat);
1520 int cch = RTTestPassedV(hTest, pszFormat, va);
1521 va_end(va);
1522
1523 return cch;
1524}
1525
1526
1527RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va)
1528{
1529 PRTTESTINT pTest = hTest;
1530 AssertPtrNull(pszFormat);
1531 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1532
1533 pTest->fSubTestSkipped = true;
1534
1535 int cch = 0;
1536 if (pszFormat && *pszFormat && pTest->enmMaxLevel >= RTTESTLVL_INFO)
1537 {
1538 va_list va2;
1539 va_copy(va2, va);
1540
1541 RTCritSectEnter(&pTest->OutputLock);
1542 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1543 RTCritSectLeave(&pTest->OutputLock);
1544
1545 va_end(va2);
1546 }
1547
1548 return cch;
1549}
1550
1551
1552RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...)
1553{
1554 va_list va;
1555
1556 va_start(va, pszFormat);
1557 int cch = RTTestSkippedV(hTest, pszFormat, va);
1558 va_end(va);
1559
1560 return cch;
1561}
1562
1563
1564
1565/**
1566 * Gets the unit name.
1567 *
1568 * @returns Unit name.
1569 * @param enmUnit The unit.
1570 */
1571static const char *rtTestUnitName(RTTESTUNIT enmUnit)
1572{
1573 switch (enmUnit)
1574 {
1575 case RTTESTUNIT_PCT: return "%";
1576 case RTTESTUNIT_BYTES: return "bytes";
1577 case RTTESTUNIT_BYTES_PER_SEC: return "bytes/s";
1578 case RTTESTUNIT_KILOBYTES: return "KB";
1579 case RTTESTUNIT_KILOBYTES_PER_SEC: return "KB/s";
1580 case RTTESTUNIT_MEGABYTES: return "MB";
1581 case RTTESTUNIT_MEGABYTES_PER_SEC: return "MB/s";
1582 case RTTESTUNIT_PACKETS: return "packets";
1583 case RTTESTUNIT_PACKETS_PER_SEC: return "packets/s";
1584 case RTTESTUNIT_FRAMES: return "frames";
1585 case RTTESTUNIT_FRAMES_PER_SEC: return "frames/s";
1586 case RTTESTUNIT_OCCURRENCES: return "occurrences";
1587 case RTTESTUNIT_OCCURRENCES_PER_SEC: return "occurrences/s";
1588 case RTTESTUNIT_ROUND_TRIP: return "roundtrips";
1589 case RTTESTUNIT_CALLS: return "calls";
1590 case RTTESTUNIT_CALLS_PER_SEC: return "calls/s";
1591 case RTTESTUNIT_SECS: return "s";
1592 case RTTESTUNIT_MS: return "ms";
1593 case RTTESTUNIT_NS: return "ns";
1594 case RTTESTUNIT_NS_PER_CALL: return "ns/call";
1595 case RTTESTUNIT_NS_PER_FRAME: return "ns/frame";
1596 case RTTESTUNIT_NS_PER_OCCURRENCE: return "ns/occurrence";
1597 case RTTESTUNIT_NS_PER_PACKET: return "ns/packet";
1598 case RTTESTUNIT_NS_PER_ROUND_TRIP: return "ns/roundtrip";
1599 case RTTESTUNIT_INSTRS: return "ins";
1600 case RTTESTUNIT_INSTRS_PER_SEC: return "ins/sec";
1601 case RTTESTUNIT_NONE: return "";
1602 case RTTESTUNIT_PP1K: return "pp1k";
1603 case RTTESTUNIT_PP10K: return "pp10k";
1604 case RTTESTUNIT_PPM: return "ppm";
1605 case RTTESTUNIT_PPB: return "ppb";
1606 case RTTESTUNIT_TICKS: return "ticks";
1607 case RTTESTUNIT_TICKS_PER_CALL: return "ticks/call";
1608 case RTTESTUNIT_TICKS_PER_OCCURENCE: return "ticks/occ";
1609 case RTTESTUNIT_PAGES: return "pages";
1610 case RTTESTUNIT_PAGES_PER_SEC: return "pages/s";
1611 case RTTESTUNIT_TICKS_PER_PAGE: return "ticks/page";
1612 case RTTESTUNIT_NS_PER_PAGE: return "ns/page";
1613 case RTTESTUNIT_PS: return "ps";
1614 case RTTESTUNIT_PS_PER_CALL: return "ps/call";
1615 case RTTESTUNIT_PS_PER_FRAME: return "ps/frame";
1616 case RTTESTUNIT_PS_PER_OCCURRENCE: return "ps/occurrence";
1617 case RTTESTUNIT_PS_PER_PACKET: return "ps/packet";
1618 case RTTESTUNIT_PS_PER_ROUND_TRIP: return "ps/roundtrip";
1619 case RTTESTUNIT_PS_PER_PAGE: return "ps/page";
1620
1621 /* No default so gcc helps us keep this up to date. */
1622 case RTTESTUNIT_INVALID:
1623 case RTTESTUNIT_END:
1624 break;
1625 }
1626 AssertMsgFailed(("%d\n", enmUnit));
1627 return "unknown";
1628}
1629
1630
1631RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit)
1632{
1633 PRTTESTINT pTest = hTest;
1634 RTTEST_GET_VALID_RETURN(pTest);
1635
1636 Assert(strlen(pszName) < 56 /* See g_kcchMaxTestValueName in testmanager/config.py. */);
1637
1638 const char *pszUnit = rtTestUnitName(enmUnit);
1639
1640 RTCritSectEnter(&pTest->Lock);
1641 rtTestXmlElem(pTest, "Value", "name=%RMas unit=%RMas value=\"%llu\"", pszName, pszUnit, u64Value);
1642 RTCritSectLeave(&pTest->Lock);
1643
1644 RTCritSectEnter(&pTest->OutputLock);
1645 rtTestPrintf(pTest, " %-58s: %'16llu %s\n", pszName, u64Value, pszUnit);
1646 RTCritSectLeave(&pTest->OutputLock);
1647
1648 return VINF_SUCCESS;
1649}
1650
1651
1652RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...)
1653{
1654 va_list va;
1655 va_start(va, pszNameFmt);
1656 int rc = RTTestValueV(hTest, u64Value, enmUnit, pszNameFmt, va);
1657 va_end(va);
1658 return rc;
1659}
1660
1661
1662RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va)
1663{
1664 char *pszName;
1665 RTStrAPrintfV(&pszName, pszNameFmt, va);
1666 if (!pszName)
1667 return VERR_NO_MEMORY;
1668 int rc = RTTestValue(hTest, pszName, u64Value, enmUnit);
1669 RTStrFree(pszName);
1670 return rc;
1671}
1672
1673
1674/**
1675 * Increments the error counter.
1676 *
1677 * @returns IPRT status code.
1678 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1679 * associated with the calling thread.
1680 */
1681RTR3DECL(int) RTTestErrorInc(RTTEST hTest)
1682{
1683 PRTTESTINT pTest = hTest;
1684 RTTEST_GET_VALID_RETURN(pTest);
1685
1686 ASMAtomicIncU32(&pTest->cErrors);
1687
1688 return VINF_SUCCESS;
1689}
1690
1691
1692
1693/**
1694 * Get the current error count.
1695 *
1696 * @returns The error counter, UINT32_MAX if no valid test handle.
1697 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1698 * associated with the calling thread.
1699 */
1700RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest)
1701{
1702 PRTTESTINT pTest = hTest;
1703 RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
1704
1705 return ASMAtomicReadU32(&pTest->cErrors);
1706}
1707
1708
1709RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest)
1710{
1711 PRTTESTINT pTest = hTest;
1712 RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
1713
1714 return ASMAtomicReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
1715}
1716
1717
1718/**
1719 * Increments the error counter and prints a failure message.
1720 *
1721 * @returns IPRT status code.
1722 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1723 * associated with the calling thread.
1724 * @param pszFormat The message. No trailing newline.
1725 * @param va The arguments.
1726 */
1727RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va)
1728{
1729 PRTTESTINT pTest = hTest;
1730 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1731
1732 RTTestErrorInc(pTest);
1733
1734 int cch = 0;
1735 if (pTest->enmMaxLevel >= RTTESTLVL_FAILURE)
1736 {
1737 va_list va2;
1738 va_copy(va2, va);
1739
1740 const char *pszEnd = strchr(pszFormat, '\0');
1741 bool fHasNewLine = pszFormat != pszEnd
1742 && pszEnd[-1] == '\n';
1743
1744 RTCritSectEnter(&pTest->OutputLock);
1745 cch += rtTestPrintf(pTest, fHasNewLine ? "%N" : "%N\n", pszFormat, &va2);
1746 if (pTest->pszErrCtx)
1747 {
1748 cch += rtTestPrintf(pTest, "context: %s\n", pTest->pszErrCtx);
1749 RTStrFree(pTest->pszErrCtx);
1750 pTest->pszErrCtx = NULL;
1751 }
1752 RTCritSectLeave(&pTest->OutputLock);
1753
1754 va_end(va2);
1755 }
1756
1757 return cch;
1758}
1759
1760
1761/**
1762 * Increments the error counter and prints a failure message.
1763 *
1764 * @returns IPRT status code.
1765 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1766 * associated with the calling thread.
1767 * @param pszFormat The message. No trailing newline.
1768 * @param ... The arguments.
1769 */
1770RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...)
1771{
1772 va_list va;
1773
1774 va_start(va, pszFormat);
1775 int cch = RTTestFailedV(hTest, pszFormat, va);
1776 va_end(va);
1777
1778 return cch;
1779}
1780
1781
1782/**
1783 * Same as RTTestPrintfV with RTTESTLVL_FAILURE.
1784 *
1785 * @returns Number of chars printed.
1786 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1787 * associated with the calling thread.
1788 * @param pszFormat The message.
1789 * @param va Arguments.
1790 */
1791RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va)
1792{
1793 return RTTestPrintfV(hTest, RTTESTLVL_FAILURE, pszFormat, va);
1794}
1795
1796
1797/**
1798 * Same as RTTestPrintf with RTTESTLVL_FAILURE.
1799 *
1800 * @returns Number of chars printed.
1801 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1802 * associated with the calling thread.
1803 * @param pszFormat The message.
1804 * @param ... Arguments.
1805 */
1806RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...)
1807{
1808 va_list va;
1809 va_start(va, pszFormat);
1810 int cch = RTTestFailureDetailsV(hTest, pszFormat, va);
1811 va_end(va);
1812 return cch;
1813}
1814
1815
1816RTR3DECL(int) RTTestErrContextV(RTTEST hTest, const char *pszFormat, va_list va)
1817{
1818 PRTTESTINT pTest = hTest;
1819 RTTEST_GET_VALID_RETURN(pTest);
1820
1821 RTStrFree(pTest->pszErrCtx);
1822 pTest->pszErrCtx = NULL;
1823
1824 if (pszFormat && *pszFormat)
1825 {
1826 pTest->pszErrCtx = RTStrAPrintf2V(pszFormat, va);
1827 AssertReturn(pTest->pszErrCtx, VERR_NO_STR_MEMORY);
1828 RTStrStripR(pTest->pszErrCtx);
1829 }
1830
1831 return VINF_SUCCESS;
1832}
1833
1834
1835RTR3DECL(int) RTTestErrContext(RTTEST hTest, const char *pszFormat, ...)
1836{
1837 va_list va;
1838 va_start(va, pszFormat);
1839 int rc = RTTestErrContextV(hTest, pszFormat, va);
1840 va_end(va);
1841 return rc;
1842}
1843
1844
1845RTR3DECL(int) RTTestDisableAssertions(RTTEST hTest)
1846{
1847 PRTTESTINT pTest = hTest;
1848 RTTEST_GET_VALID_RETURN(pTest);
1849
1850 uint32_t cTimes = ASMAtomicIncU32(&pTest->cAssertionsDisabledAndQuieted);
1851 if (cTimes >= 2 && cTimes <= 8)
1852 return VINF_SUCCESS;
1853 if (cTimes > 8)
1854 {
1855 RTAssertSetMayPanic(pTest->fAssertSavedMayPanic);
1856 RTAssertSetQuiet(pTest->fAssertSavedQuiet);
1857 Assert(cTimes <= 8);
1858 }
1859 pTest->fAssertSavedMayPanic = RTAssertSetMayPanic(false);
1860 pTest->fAssertSavedQuiet = RTAssertSetQuiet(true);
1861 return VINF_SUCCESS;
1862}
1863
1864
1865RTR3DECL(int) RTTestRestoreAssertions(RTTEST hTest)
1866{
1867 PRTTESTINT pTest = hTest;
1868 RTTEST_GET_VALID_RETURN(pTest);
1869
1870 uint32_t cTimes = ASMAtomicDecU32(&pTest->cAssertionsDisabledAndQuieted);
1871 if (cTimes == 0)
1872 {
1873 RTAssertSetMayPanic(pTest->fAssertSavedMayPanic);
1874 RTAssertSetQuiet(pTest->fAssertSavedQuiet);
1875 }
1876 else
1877 AssertStmt(cTimes < UINT32_MAX / 2, ASMAtomicIncU32(&pTest->cAssertionsDisabledAndQuieted));
1878 return VINF_SUCCESS;
1879}
1880
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