VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use