VirtualBox

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

Last change on this file since 27653 was 27649, checked in by vboxsync, 15 years ago

RTTest: Added RTTest*Value* for reporting simple benchmark result. Implemented the test pipe + file.

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