VirtualBox

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

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

IPRT/r3/test.cpp: No element values, only attribute values. Simplifies parsing.

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

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