VirtualBox

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

Last change on this file since 46298 was 46298, checked in by vboxsync, 12 years ago

RTTest: Added some new features/APIs for forwarding bootsector test results.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette