VirtualBox

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

Last change on this file since 88956 was 88311, checked in by vboxsync, 4 years ago

IPRT/test: Added RTTestErrContext (with variations) for setting a print-once-on-failure message to help put a failure in context w/o needing to get verbose on successful runs. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.5 KB
Line 
1/* $Id: test.cpp 88311 2021-03-29 12:59:22Z vboxsync $ */
2/** @file
3 * IPRT - Testcase Framework.
4 */
5
6/*
7 * Copyright (C) 2009-2020 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 * Emit an XML element that doesn't have any value and instead ends immediately.
813 *
814 * The caller must own the instance lock.
815 *
816 * @param pTest The test instance.
817 * @param pszTag The element tag.
818 * @param pszAttrFmt The element attributes as a format string. Use
819 * NULL if none.
820 * @param va Format string arguments.
821 */
822static void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
823{
824 if (pTest->fXmlEnabled)
825 {
826 RTTIMESPEC TimeSpec;
827 RTTIME Time;
828 char szTS[80];
829 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
830
831 if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
832 rtTestXmlOutput(pTest, "\n");
833
834 if (!pszAttrFmt || !*pszAttrFmt)
835 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas/>\n",
836 pTest->cXmlElements * 2, "", pszTag, szTS);
837 else
838 {
839 va_list va2;
840 va_copy(va2, va);
841 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N/>\n",
842 pTest->cXmlElements * 2, "", pszTag, szTS, pszAttrFmt, &va2);
843 va_end(va2);
844 }
845 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
846 }
847}
848
849/**
850 * Wrapper around rtTestXmlElemV.
851 */
852static void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
853{
854 va_list va;
855 va_start(va, pszAttrFmt);
856 rtTestXmlElemV(pTest, pszTag, pszAttrFmt, va);
857 va_end(va);
858}
859
860
861/**
862 * Starts a new XML element.
863 *
864 * The caller must own the instance lock.
865 *
866 * @param pTest The test instance.
867 * @param pszTag The element tag.
868 * @param pszAttrFmt The element attributes as a format string. Use
869 * NULL if none.
870 * @param va Format string arguments.
871 */
872static void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
873{
874 /* Push it onto the stack. */
875 size_t i = pTest->cXmlElements;
876 AssertReturnVoid(i < RT_ELEMENTS(pTest->apszXmlElements));
877 pTest->apszXmlElements[i] = pszTag;
878 pTest->cXmlElements = i + 1;
879
880 if (pTest->fXmlEnabled)
881 {
882 RTTIMESPEC TimeSpec;
883 RTTIME Time;
884 char szTS[80];
885 RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
886
887 if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
888 rtTestXmlOutput(pTest, "\n");
889
890 if (!pszAttrFmt || !*pszAttrFmt)
891 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas>",
892 i * 2, "", pszTag, szTS);
893 else
894 {
895 va_list va2;
896 va_copy(va2, va);
897 rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N>",
898 i * 2, "", pszTag, szTS, pszAttrFmt, &va2);
899 va_end(va2);
900 }
901 pTest->eXmlState = RTTESTINT::kXmlPos_ValueStart;
902 }
903}
904
905
906/**
907 * Wrapper around rtTestXmlElemStartV.
908 */
909static void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
910{
911 va_list va;
912 va_start(va, pszAttrFmt);
913 rtTestXmlElemStartV(pTest, pszTag, pszAttrFmt, va);
914 va_end(va);
915}
916
917
918/**
919 * Ends the current element.
920 *
921 * The caller must own the instance lock.
922 *
923 * @param pTest The test instance.
924 * @param pszTag The tag we're ending (chiefly for sanity
925 * checking).
926 */
927static void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag)
928{
929 /* pop the element */
930 size_t i = pTest->cXmlElements;
931 AssertReturnVoid(i > 0);
932 i--;
933 AssertReturnVoid(!strcmp(pszTag, pTest->apszXmlElements[i]));
934 pTest->cXmlElements = i;
935
936 /* Do the closing. */
937 if (pTest->fXmlEnabled)
938 {
939 if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
940 rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
941 else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
942 rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
943 else
944 rtTestXmlOutput(pTest, "</%s>\n", pszTag);
945 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
946 }
947}
948
949
950/**
951 * Ends the XML stream, closing all open elements.
952 *
953 * The caller must own the instance lock.
954 *
955 * @param pTest The test instance.
956 */
957static void rtTestXmlEnd(PRTTESTINT pTest)
958{
959 if (pTest->fXmlEnabled)
960 {
961 /*
962 * Close all the elements and add the final TestEnd one to get a
963 * final timestamp and some certainty that the XML is valid.
964 */
965 size_t i = pTest->cXmlElements;
966 AssertReturnVoid(i > 0 || pTest->fXmlOmitTopTest || !pTest->fXmlTopTestDone);
967 while (i-- > 1)
968 {
969 const char *pszTag = pTest->apszXmlElements[pTest->cXmlElements];
970 if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
971 rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
972 else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
973 rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
974 else
975 rtTestXmlOutput(pTest, "</%s>\n", pszTag);
976 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
977 }
978
979 if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone)
980 {
981 rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"",
982 pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors);
983 rtTestXmlOutput(pTest, "</Test>\n");
984 }
985
986 /*
987 * Close the XML outputs.
988 */
989 if (pTest->hXmlPipe != NIL_RTPIPE)
990 {
991 RTPipeClose(pTest->hXmlPipe);
992 pTest->hXmlPipe = NIL_RTPIPE;
993 }
994 if (pTest->hXmlFile != NIL_RTFILE)
995 {
996 RTFileClose(pTest->hXmlFile);
997 pTest->hXmlFile = NIL_RTFILE;
998 }
999 pTest->fXmlEnabled = false;
1000 pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
1001 }
1002 pTest->cXmlElements = 0;
1003}
1004
1005/**
1006 * Output callback.
1007 *
1008 * @returns number of bytes written.
1009 * @param pvArg User argument.
1010 * @param pachChars Pointer to an array of utf-8 characters.
1011 * @param cbChars Number of bytes in the character array pointed to by pachChars.
1012 */
1013static DECLCALLBACK(size_t) rtTestPrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
1014{
1015 size_t cch = 0;
1016 PRTTESTINT pTest = (PRTTESTINT)pvArg;
1017 if (cbChars)
1018 {
1019 do
1020 {
1021 /* insert prefix if at a newline. */
1022 if (pTest->fNewLine)
1023 {
1024 RTStrmWrite(pTest->pOutStrm, pTest->pszTest, pTest->cchTest);
1025 RTStrmWrite(pTest->pOutStrm, ": ", 2);
1026 cch += 2 + pTest->cchTest;
1027 }
1028
1029 /* look for newline and write the stuff. */
1030 const char *pchEnd = (const char *)memchr(pachChars, '\n', cbChars);
1031 if (!pchEnd)
1032 {
1033 pTest->fNewLine = false;
1034 RTStrmWrite(pTest->pOutStrm, pachChars, cbChars);
1035 cch += cbChars;
1036 break;
1037 }
1038
1039 pTest->fNewLine = true;
1040 size_t const cchPart = pchEnd - pachChars + 1;
1041 RTStrmWrite(pTest->pOutStrm, pachChars, cchPart);
1042 cch += cchPart;
1043 pachChars += cchPart;
1044 cbChars -= cchPart;
1045 } while (cbChars);
1046 }
1047 else
1048 RTStrmFlush(pTest->pOutStrm);
1049 return cch;
1050}
1051
1052
1053/**
1054 * Internal output worker.
1055 *
1056 * Caller takes the lock.
1057 *
1058 * @returns Number of chars printed.
1059 * @param pTest The test instance.
1060 * @param pszFormat The message.
1061 * @param va The arguments.
1062 */
1063static int rtTestPrintfV(PRTTESTINT pTest, const char *pszFormat, va_list va)
1064{
1065 return (int)RTStrFormatV(rtTestPrintfOutput, pTest, NULL, NULL, pszFormat, va);
1066}
1067
1068
1069/**
1070 * Internal output worker.
1071 *
1072 * Caller takes the lock.
1073 *
1074 * @returns Number of chars printed.
1075 * @param pTest The test instance.
1076 * @param pszFormat The message.
1077 * @param ... The arguments.
1078 */
1079static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...)
1080{
1081 va_list va;
1082
1083 va_start(va, pszFormat);
1084 int cch = rtTestPrintfV(pTest, pszFormat, va);
1085 va_end(va);
1086
1087 return cch;
1088}
1089
1090
1091/**
1092 * Test vprintf making sure the output starts on a new line.
1093 *
1094 * @returns Number of chars printed.
1095 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1096 * associated with the calling thread.
1097 * @param enmLevel Message importance level.
1098 * @param pszFormat The message.
1099 * @param va Arguments.
1100 */
1101RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
1102{
1103 PRTTESTINT pTest = hTest;
1104 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1105
1106 RTCritSectEnter(&pTest->OutputLock);
1107
1108 int cch = 0;
1109 if (enmLevel <= pTest->enmMaxLevel)
1110 {
1111 if (!pTest->fNewLine)
1112 cch += rtTestPrintf(pTest, "\n");
1113 cch += rtTestPrintfV(pTest, pszFormat, va);
1114 }
1115
1116 RTCritSectLeave(&pTest->OutputLock);
1117
1118 return cch;
1119}
1120
1121
1122/**
1123 * Test printf making sure the output starts on a new line.
1124 *
1125 * @returns Number of chars printed.
1126 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1127 * associated with the calling thread.
1128 * @param enmLevel Message importance level.
1129 * @param pszFormat The message.
1130 * @param ... Arguments.
1131 */
1132RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
1133{
1134 va_list va;
1135
1136 va_start(va, pszFormat);
1137 int cch = RTTestPrintfNlV(hTest, enmLevel, pszFormat, va);
1138 va_end(va);
1139
1140 return cch;
1141}
1142
1143
1144/**
1145 * Test vprintf, makes sure lines are prefixed and so forth.
1146 *
1147 * @returns Number of chars printed.
1148 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1149 * associated with the calling thread.
1150 * @param enmLevel Message importance level.
1151 * @param pszFormat The message.
1152 * @param va Arguments.
1153 */
1154RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
1155{
1156 PRTTESTINT pTest = hTest;
1157 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1158
1159 RTCritSectEnter(&pTest->OutputLock);
1160 int cch = 0;
1161 if (enmLevel <= pTest->enmMaxLevel)
1162 cch += rtTestPrintfV(pTest, pszFormat, va);
1163 RTCritSectLeave(&pTest->OutputLock);
1164
1165 return cch;
1166}
1167
1168
1169/**
1170 * Test printf, makes sure lines are prefixed and so forth.
1171 *
1172 * @returns Number of chars printed.
1173 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1174 * associated with the calling thread.
1175 * @param enmLevel Message importance level.
1176 * @param pszFormat The message.
1177 * @param ... Arguments.
1178 */
1179RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
1180{
1181 va_list va;
1182
1183 va_start(va, pszFormat);
1184 int cch = RTTestPrintfV(hTest, enmLevel, pszFormat, va);
1185 va_end(va);
1186
1187 return cch;
1188}
1189
1190
1191/**
1192 * Prints the test banner.
1193 *
1194 * @returns Number of chars printed.
1195 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1196 * associated with the calling thread.
1197 */
1198RTR3DECL(int) RTTestBanner(RTTEST hTest)
1199{
1200 return RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "TESTING...\n");
1201}
1202
1203
1204/**
1205 * Prints the result of a sub-test if necessary.
1206 *
1207 * @returns Number of chars printed.
1208 * @param pTest The test instance.
1209 * @remarks Caller own the test Lock.
1210 */
1211static int rtTestSubTestReport(PRTTESTINT pTest)
1212{
1213 int cch = 0;
1214 if ( !pTest->fSubTestReported
1215 && pTest->pszSubTest)
1216 {
1217 pTest->fSubTestReported = true;
1218 uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
1219 if (!cErrors)
1220 {
1221 if (!pTest->fSubTestSkipped)
1222 {
1223 rtTestXmlElem(pTest, "Passed", NULL);
1224 rtTestXmlElemEnd(pTest, "Test");
1225 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: PASSED\n", pTest->pszSubTest);
1226 }
1227 else
1228 {
1229 rtTestXmlElem(pTest, "Skipped", NULL);
1230 rtTestXmlElemEnd(pTest, "Test");
1231 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: SKIPPED\n", pTest->pszSubTest);
1232 }
1233 }
1234 else
1235 {
1236 pTest->cSubTestsFailed++;
1237 rtTestXmlElem(pTest, "Failed", "errors=\"%u\"", cErrors);
1238 rtTestXmlElemEnd(pTest, "Test");
1239 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-60s: FAILED (%u errors)\n",
1240 pTest->pszSubTest, cErrors);
1241 }
1242 }
1243 return cch;
1244}
1245
1246
1247/**
1248 * RTTestSub and RTTestSubDone worker that cleans up the current (if any)
1249 * sub test.
1250 *
1251 * @returns Number of chars printed.
1252 * @param pTest The test instance.
1253 * @remarks Caller own the test Lock.
1254 */
1255static int rtTestSubCleanup(PRTTESTINT pTest)
1256{
1257 int cch = 0;
1258 if (pTest->pszSubTest)
1259 {
1260 cch += rtTestSubTestReport(pTest);
1261
1262 RTStrFree((char *)pTest->pszSubTest);
1263 pTest->pszSubTest = NULL;
1264 pTest->fSubTestReported = true;
1265 }
1266 RTStrFree(pTest->pszErrCtx);
1267 pTest->pszErrCtx = NULL;
1268 return cch;
1269}
1270
1271
1272/**
1273 * Summaries the test, destroys the test instance and return an exit code.
1274 *
1275 * @returns Test program exit code.
1276 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1277 * associated with the calling thread.
1278 */
1279RTR3DECL(RTEXITCODE) RTTestSummaryAndDestroy(RTTEST hTest)
1280{
1281 PRTTESTINT pTest = hTest;
1282 RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_FAILURE);
1283
1284 RTCritSectEnter(&pTest->Lock);
1285 rtTestSubTestReport(pTest);
1286 RTCritSectLeave(&pTest->Lock);
1287
1288 RTEXITCODE enmExitCode;
1289 if (!pTest->cErrors)
1290 {
1291 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SUCCESS\n");
1292 enmExitCode = RTEXITCODE_SUCCESS;
1293 }
1294 else
1295 {
1296 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
1297 enmExitCode = RTEXITCODE_FAILURE;
1298 }
1299
1300 RTTestDestroy(pTest);
1301 return enmExitCode;
1302}
1303
1304
1305RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va)
1306{
1307 PRTTESTINT pTest = hTest;
1308 RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_SKIPPED);
1309
1310 RTCritSectEnter(&pTest->Lock);
1311 rtTestSubTestReport(pTest);
1312 RTCritSectLeave(&pTest->Lock);
1313
1314 RTEXITCODE enmExitCode;
1315 if (!pTest->cErrors)
1316 {
1317 if (pszReasonFmt)
1318 RTTestPrintfNlV(hTest, RTTESTLVL_FAILURE, pszReasonFmt, va);
1319 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SKIPPED\n");
1320 enmExitCode = RTEXITCODE_SKIPPED;
1321 }
1322 else
1323 {
1324 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
1325 enmExitCode = RTEXITCODE_FAILURE;
1326 }
1327
1328 RTTestDestroy(pTest);
1329 return enmExitCode;
1330}
1331
1332
1333RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...)
1334{
1335 va_list va;
1336 va_start(va, pszReasonFmt);
1337 RTEXITCODE enmExitCode = RTTestSkipAndDestroyV(hTest, pszReasonFmt, va);
1338 va_end(va);
1339 return enmExitCode;
1340}
1341
1342
1343/**
1344 * Starts a sub-test.
1345 *
1346 * This will perform an implicit RTTestSubDone() call if that has not been done
1347 * since the last RTTestSub call.
1348 *
1349 * @returns Number of chars printed.
1350 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1351 * associated with the calling thread.
1352 * @param pszSubTest The sub-test name
1353 */
1354RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest)
1355{
1356 PRTTESTINT pTest = hTest;
1357 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1358
1359 RTCritSectEnter(&pTest->Lock);
1360
1361 /* Cleanup, reporting if necessary previous sub test. */
1362 rtTestSubCleanup(pTest);
1363
1364 /* Start new sub test. */
1365 pTest->cSubTests++;
1366 pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors);
1367 pTest->pszSubTest = RTStrDup(pszSubTest);
1368 pTest->cchSubTest = strlen(pszSubTest);
1369 Assert(pTest->cchSubTest < 64 /* See g_kcchMaxTestResultName in testmanager/config.py. */);
1370 pTest->fSubTestSkipped = false;
1371 pTest->fSubTestReported = false;
1372
1373 int cch = 0;
1374 if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
1375 cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
1376
1377 if (!pTest->fXmlTopTestDone)
1378 {
1379 pTest->fXmlTopTestDone = true;
1380 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pTest->pszTest);
1381 }
1382
1383 rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszSubTest);
1384
1385 RTCritSectLeave(&pTest->Lock);
1386
1387 return cch;
1388}
1389
1390
1391/**
1392 * Format string version of RTTestSub.
1393 *
1394 * See RTTestSub for details.
1395 *
1396 * @returns Number of chars printed.
1397 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1398 * associated with the calling thread.
1399 * @param pszSubTestFmt The sub-test name format string.
1400 * @param ... Arguments.
1401 */
1402RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...)
1403{
1404 va_list va;
1405 va_start(va, pszSubTestFmt);
1406 int cch = RTTestSubV(hTest, pszSubTestFmt, va);
1407 va_end(va);
1408 return cch;
1409}
1410
1411
1412/**
1413 * Format string version of RTTestSub.
1414 *
1415 * See RTTestSub for details.
1416 *
1417 * @returns Number of chars printed.
1418 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1419 * associated with the calling thread.
1420 * @param pszSubTestFmt The sub-test name format string.
1421 * @param ... Arguments.
1422 */
1423RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va)
1424{
1425 char *pszSubTest;
1426 RTStrAPrintfV(&pszSubTest, pszSubTestFmt, va);
1427 if (pszSubTest)
1428 {
1429 int cch = RTTestSub(hTest, pszSubTest);
1430 RTStrFree(pszSubTest);
1431 return cch;
1432 }
1433 return 0;
1434}
1435
1436
1437/**
1438 * Completes a sub-test.
1439 *
1440 * @returns Number of chars printed.
1441 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1442 * associated with the calling thread.
1443 */
1444RTR3DECL(int) RTTestSubDone(RTTEST hTest)
1445{
1446 PRTTESTINT pTest = hTest;
1447 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1448
1449 RTCritSectEnter(&pTest->Lock);
1450 int cch = rtTestSubCleanup(pTest);
1451 RTCritSectLeave(&pTest->Lock);
1452
1453 return cch;
1454}
1455
1456/**
1457 * Prints an extended PASSED message, optional.
1458 *
1459 * This does not conclude the sub-test, it could be used to report the passing
1460 * of a sub-sub-to-the-power-of-N-test.
1461 *
1462 * @returns IPRT status code.
1463 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1464 * associated with the calling thread.
1465 * @param pszFormat The message. No trailing newline.
1466 * @param va The arguments.
1467 */
1468RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
1469{
1470 PRTTESTINT pTest = hTest;
1471 AssertPtr(pszFormat);
1472 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1473
1474 int cch = 0;
1475 if (pTest->enmMaxLevel >= RTTESTLVL_INFO)
1476 {
1477 va_list va2;
1478 va_copy(va2, va);
1479
1480 RTCritSectEnter(&pTest->OutputLock);
1481 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1482 RTCritSectLeave(&pTest->OutputLock);
1483
1484 va_end(va2);
1485 }
1486
1487 return cch;
1488}
1489
1490
1491/**
1492 * Prints an extended PASSED message, optional.
1493 *
1494 * This does not conclude the sub-test, it could be used to report the passing
1495 * of a sub-sub-to-the-power-of-N-test.
1496 *
1497 * @returns IPRT status code.
1498 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1499 * associated with the calling thread.
1500 * @param pszFormat The message. No trailing newline.
1501 * @param ... The arguments.
1502 */
1503RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...)
1504{
1505 va_list va;
1506
1507 va_start(va, pszFormat);
1508 int cch = RTTestPassedV(hTest, pszFormat, va);
1509 va_end(va);
1510
1511 return cch;
1512}
1513
1514
1515RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va)
1516{
1517 PRTTESTINT pTest = hTest;
1518 AssertPtrNull(pszFormat);
1519 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1520
1521 pTest->fSubTestSkipped = true;
1522
1523 int cch = 0;
1524 if (pszFormat && *pszFormat && pTest->enmMaxLevel >= RTTESTLVL_INFO)
1525 {
1526 va_list va2;
1527 va_copy(va2, va);
1528
1529 RTCritSectEnter(&pTest->OutputLock);
1530 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1531 RTCritSectLeave(&pTest->OutputLock);
1532
1533 va_end(va2);
1534 }
1535
1536 return cch;
1537}
1538
1539
1540RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...)
1541{
1542 va_list va;
1543
1544 va_start(va, pszFormat);
1545 int cch = RTTestSkippedV(hTest, pszFormat, va);
1546 va_end(va);
1547
1548 return cch;
1549}
1550
1551
1552
1553/**
1554 * Gets the unit name.
1555 *
1556 * @returns Unit name.
1557 * @param enmUnit The unit.
1558 */
1559static const char *rtTestUnitName(RTTESTUNIT enmUnit)
1560{
1561 switch (enmUnit)
1562 {
1563 case RTTESTUNIT_PCT: return "%";
1564 case RTTESTUNIT_BYTES: return "bytes";
1565 case RTTESTUNIT_BYTES_PER_SEC: return "bytes/s";
1566 case RTTESTUNIT_KILOBYTES: return "KB";
1567 case RTTESTUNIT_KILOBYTES_PER_SEC: return "KB/s";
1568 case RTTESTUNIT_MEGABYTES: return "MB";
1569 case RTTESTUNIT_MEGABYTES_PER_SEC: return "MB/s";
1570 case RTTESTUNIT_PACKETS: return "packets";
1571 case RTTESTUNIT_PACKETS_PER_SEC: return "packets/s";
1572 case RTTESTUNIT_FRAMES: return "frames";
1573 case RTTESTUNIT_FRAMES_PER_SEC: return "frames/s";
1574 case RTTESTUNIT_OCCURRENCES: return "occurrences";
1575 case RTTESTUNIT_OCCURRENCES_PER_SEC: return "occurrences/s";
1576 case RTTESTUNIT_ROUND_TRIP: return "roundtrips";
1577 case RTTESTUNIT_CALLS: return "calls";
1578 case RTTESTUNIT_CALLS_PER_SEC: return "calls/s";
1579 case RTTESTUNIT_SECS: return "s";
1580 case RTTESTUNIT_MS: return "ms";
1581 case RTTESTUNIT_NS: return "ns";
1582 case RTTESTUNIT_NS_PER_CALL: return "ns/call";
1583 case RTTESTUNIT_NS_PER_FRAME: return "ns/frame";
1584 case RTTESTUNIT_NS_PER_OCCURRENCE: return "ns/occurrence";
1585 case RTTESTUNIT_NS_PER_PACKET: return "ns/packet";
1586 case RTTESTUNIT_NS_PER_ROUND_TRIP: return "ns/roundtrip";
1587 case RTTESTUNIT_INSTRS: return "ins";
1588 case RTTESTUNIT_INSTRS_PER_SEC: return "ins/sec";
1589 case RTTESTUNIT_NONE: return "";
1590 case RTTESTUNIT_PP1K: return "pp1k";
1591 case RTTESTUNIT_PP10K: return "pp10k";
1592 case RTTESTUNIT_PPM: return "ppm";
1593 case RTTESTUNIT_PPB: return "ppb";
1594
1595 /* No default so gcc helps us keep this up to date. */
1596 case RTTESTUNIT_INVALID:
1597 case RTTESTUNIT_END:
1598 break;
1599 }
1600 AssertMsgFailed(("%d\n", enmUnit));
1601 return "unknown";
1602}
1603
1604
1605RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit)
1606{
1607 PRTTESTINT pTest = hTest;
1608 RTTEST_GET_VALID_RETURN(pTest);
1609
1610 Assert(strlen(pszName) < 56 /* See g_kcchMaxTestValueName in testmanager/config.py. */);
1611
1612 const char *pszUnit = rtTestUnitName(enmUnit);
1613
1614 RTCritSectEnter(&pTest->Lock);
1615 rtTestXmlElem(pTest, "Value", "name=%RMas unit=%RMas value=\"%llu\"", pszName, pszUnit, u64Value);
1616 RTCritSectLeave(&pTest->Lock);
1617
1618 RTCritSectEnter(&pTest->OutputLock);
1619 rtTestPrintf(pTest, " %-58s: %'16llu %s\n", pszName, u64Value, pszUnit);
1620 RTCritSectLeave(&pTest->OutputLock);
1621
1622 return VINF_SUCCESS;
1623}
1624
1625
1626RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...)
1627{
1628 va_list va;
1629 va_start(va, pszNameFmt);
1630 int rc = RTTestValueV(hTest, u64Value, enmUnit, pszNameFmt, va);
1631 va_end(va);
1632 return rc;
1633}
1634
1635
1636RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va)
1637{
1638 char *pszName;
1639 RTStrAPrintfV(&pszName, pszNameFmt, va);
1640 if (!pszName)
1641 return VERR_NO_MEMORY;
1642 int rc = RTTestValue(hTest, pszName, u64Value, enmUnit);
1643 RTStrFree(pszName);
1644 return rc;
1645}
1646
1647
1648/**
1649 * Increments the error counter.
1650 *
1651 * @returns IPRT status code.
1652 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1653 * associated with the calling thread.
1654 */
1655RTR3DECL(int) RTTestErrorInc(RTTEST hTest)
1656{
1657 PRTTESTINT pTest = hTest;
1658 RTTEST_GET_VALID_RETURN(pTest);
1659
1660 ASMAtomicIncU32(&pTest->cErrors);
1661
1662 return VINF_SUCCESS;
1663}
1664
1665
1666
1667/**
1668 * Get the current error count.
1669 *
1670 * @returns The error counter, UINT32_MAX if no valid test handle.
1671 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1672 * associated with the calling thread.
1673 */
1674RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest)
1675{
1676 PRTTESTINT pTest = hTest;
1677 RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
1678
1679 return ASMAtomicReadU32(&pTest->cErrors);
1680}
1681
1682
1683RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest)
1684{
1685 PRTTESTINT pTest = hTest;
1686 RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
1687
1688 return ASMAtomicReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
1689}
1690
1691
1692/**
1693 * Increments the error counter and prints a failure message.
1694 *
1695 * @returns IPRT status code.
1696 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1697 * associated with the calling thread.
1698 * @param pszFormat The message. No trailing newline.
1699 * @param va The arguments.
1700 */
1701RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va)
1702{
1703 PRTTESTINT pTest = hTest;
1704 RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
1705
1706 RTTestErrorInc(pTest);
1707
1708 int cch = 0;
1709 if (pTest->enmMaxLevel >= RTTESTLVL_FAILURE)
1710 {
1711 va_list va2;
1712 va_copy(va2, va);
1713
1714 const char *pszEnd = strchr(pszFormat, '\0');
1715 bool fHasNewLine = pszFormat != pszEnd
1716 && pszEnd[-1] == '\n';
1717
1718 RTCritSectEnter(&pTest->OutputLock);
1719 cch += rtTestPrintf(pTest, fHasNewLine ? "%N" : "%N\n", pszFormat, &va2);
1720 if (pTest->pszErrCtx)
1721 {
1722 cch += rtTestPrintf(pTest, "context: %s\n", pTest->pszErrCtx);
1723 RTStrFree(pTest->pszErrCtx);
1724 pTest->pszErrCtx = NULL;
1725 }
1726 RTCritSectLeave(&pTest->OutputLock);
1727
1728 va_end(va2);
1729 }
1730
1731 return cch;
1732}
1733
1734
1735/**
1736 * Increments the error counter and prints a failure message.
1737 *
1738 * @returns IPRT status code.
1739 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1740 * associated with the calling thread.
1741 * @param pszFormat The message. No trailing newline.
1742 * @param ... The arguments.
1743 */
1744RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...)
1745{
1746 va_list va;
1747
1748 va_start(va, pszFormat);
1749 int cch = RTTestFailedV(hTest, pszFormat, va);
1750 va_end(va);
1751
1752 return cch;
1753}
1754
1755
1756/**
1757 * Same as RTTestPrintfV with RTTESTLVL_FAILURE.
1758 *
1759 * @returns Number of chars printed.
1760 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1761 * associated with the calling thread.
1762 * @param pszFormat The message.
1763 * @param va Arguments.
1764 */
1765RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va)
1766{
1767 return RTTestPrintfV(hTest, RTTESTLVL_FAILURE, pszFormat, va);
1768}
1769
1770
1771/**
1772 * Same as RTTestPrintf with RTTESTLVL_FAILURE.
1773 *
1774 * @returns Number of chars printed.
1775 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1776 * associated with the calling thread.
1777 * @param pszFormat The message.
1778 * @param ... Arguments.
1779 */
1780RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...)
1781{
1782 va_list va;
1783 va_start(va, pszFormat);
1784 int cch = RTTestFailureDetailsV(hTest, pszFormat, va);
1785 va_end(va);
1786 return cch;
1787}
1788
1789
1790RTR3DECL(int) RTTestErrContextV(RTTEST hTest, const char *pszFormat, va_list va)
1791{
1792 PRTTESTINT pTest = hTest;
1793 RTTEST_GET_VALID_RETURN(pTest);
1794
1795 RTStrFree(pTest->pszErrCtx);
1796 pTest->pszErrCtx = NULL;
1797
1798 if (pszFormat && *pszFormat)
1799 {
1800 pTest->pszErrCtx = RTStrAPrintf2V(pszFormat, va);
1801 AssertReturn(pTest->pszErrCtx, VERR_NO_STR_MEMORY);
1802 RTStrStripR(pTest->pszErrCtx);
1803 }
1804
1805 return VINF_SUCCESS;
1806}
1807
1808
1809RTR3DECL(int) RTTestErrContext(RTTEST hTest, const char *pszFormat, ...)
1810{
1811 va_list va;
1812 va_start(va, pszFormat);
1813 int rc = RTTestErrContextV(hTest, pszFormat, va);
1814 va_end(va);
1815 return rc;
1816}
1817
1818
1819RTR3DECL(int) RTTestDisableAssertions(RTTEST hTest)
1820{
1821 PRTTESTINT pTest = hTest;
1822 RTTEST_GET_VALID_RETURN(pTest);
1823
1824 uint32_t cTimes = ASMAtomicIncU32(&pTest->cAssertionsDisabledAndQuieted);
1825 if (cTimes >= 2 && cTimes <= 8)
1826 return VINF_SUCCESS;
1827 if (cTimes > 8)
1828 {
1829 RTAssertSetMayPanic(pTest->fAssertSavedMayPanic);
1830 RTAssertSetQuiet(pTest->fAssertSavedQuiet);
1831 Assert(cTimes <= 8);
1832 }
1833 pTest->fAssertSavedMayPanic = RTAssertSetMayPanic(false);
1834 pTest->fAssertSavedQuiet = RTAssertSetQuiet(true);
1835 return VINF_SUCCESS;
1836}
1837
1838
1839RTR3DECL(int) RTTestRestoreAssertions(RTTEST hTest)
1840{
1841 PRTTESTINT pTest = hTest;
1842 RTTEST_GET_VALID_RETURN(pTest);
1843
1844 uint32_t cTimes = ASMAtomicDecU32(&pTest->cAssertionsDisabledAndQuieted);
1845 if (cTimes == 0)
1846 {
1847 RTAssertSetMayPanic(pTest->fAssertSavedMayPanic);
1848 RTAssertSetQuiet(pTest->fAssertSavedQuiet);
1849 }
1850 else
1851 AssertStmt(cTimes < UINT32_MAX / 2, ASMAtomicIncU32(&pTest->cAssertionsDisabledAndQuieted));
1852 return VINF_SUCCESS;
1853}
1854
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