VirtualBox

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

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

Extended RTOnce with termination cleanups. (Changes existing structures and functions.)

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