VirtualBox

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

Last change on this file since 34405 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

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