VirtualBox

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

Last change on this file since 93943 was 93754, checked in by vboxsync, 3 years ago

IPRT,ValKit,VMMDevTesting.h: Added picoseconds to the test units. bugref:9898

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