VirtualBox

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

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

tstRTTime: Renamed from tstTime, convert to RTTest and restricted the amount of output.

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