VirtualBox

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

Last change on this file since 55998 was 52380, checked in by vboxsync, 10 years ago

Runtime: comment nit.

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

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