VirtualBox

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

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

IPRT: Added RTTestInitAndCreate - a combination of RTR3Init and RTTestCreate.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.3 KB
Line 
1/* $Id: test.cpp 20605 2009-06-15 20:49:41Z 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/initterm.h>
42#include <iprt/mem.h>
43#include <iprt/once.h>
44#include <iprt/param.h>
45#include <iprt/string.h>
46#include <iprt/stream.h>
47
48#include "internal/magics.h"
49
50
51/*******************************************************************************
52* Structures and Typedefs *
53*******************************************************************************/
54/**
55 * Guarded memory allocation record.
56 */
57typedef struct RTTESTGUARDEDMEM
58{
59 /** Pointer to the next record. */
60 struct RTTESTGUARDEDMEM *pNext;
61 /** The address we return to the user. */
62 void *pvUser;
63 /** The base address of the allocation. */
64 void *pvAlloc;
65 /** The size of the allocation. */
66 size_t cbAlloc;
67 /** Guards. */
68 struct
69 {
70 /** The guard address. */
71 void *pv;
72 /** The guard size. */
73 size_t cb;
74 } aGuards[2];
75} RTTESTGUARDEDMEM;
76/** Pointer to an guarded memory allocation. */
77typedef RTTESTGUARDEDMEM *PRTTESTGUARDEDMEM;
78
79/**
80 * Test instance structure.
81 */
82typedef struct RTTESTINT
83{
84 /** Magic. */
85 uint32_t u32Magic;
86 /** The number of errors. */
87 volatile uint32_t cErrors;
88 /** The test name. */
89 const char *pszTest;
90 /** The length of the test name. */
91 size_t cchTest;
92 /** The size of a guard. Multiple of PAGE_SIZE. */
93 uint32_t cbGuard;
94 /** The verbosity level. */
95 RTTESTLVL enmMaxLevel;
96
97
98 /** Critical section seralizing output. */
99 RTCRITSECT OutputLock;
100 /** The output stream. */
101 PRTSTREAM pOutStrm;
102 /** Whether we're currently at a newline. */
103 bool fNewLine;
104
105
106 /** Critical section seralizing access to the members following it. */
107 RTCRITSECT Lock;
108
109 /** The list of guarded memory allocations. */
110 PRTTESTGUARDEDMEM pGuardedMem;
111
112 /** The current sub-test. */
113 const char *pszSubTest;
114 /** The lenght of the sub-test name. */
115 size_t cchSubTest;
116 /** Whether we've reported the sub-test result or not. */
117 bool fSubTestReported;
118 /** The start error count of the current subtest. */
119 uint32_t cSubTestAtErrors;
120
121 /** The number of sub tests. */
122 uint32_t cSubTests;
123 /** The number of sub tests that failed. */
124 uint32_t cSubTestsFailed;
125
126} RTTESTINT;
127/** Pointer to a test instance. */
128typedef RTTESTINT *PRTTESTINT;
129
130
131/*******************************************************************************
132* Defined Constants And Macros *
133*******************************************************************************/
134/** Validate a test instance. */
135#define RTTEST_VALID_RETURN(pTest) \
136 do { \
137 AssertPtrReturn(pTest, VERR_INVALID_HANDLE); \
138 AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, VERR_INVALID_HANDLE); \
139 } while (0)
140
141/** Gets and validates a test instance.
142 * If the handle is nil, we will try retrive it from the test TLS entry.
143 */
144#define RTTEST_GET_VALID_RETURN(pTest) \
145 do { \
146 if (pTest == NIL_RTTEST) \
147 pTest = (PRTTESTINT)RTTlsGet(g_iTestTls); \
148 AssertPtrReturn(pTest, VERR_INVALID_HANDLE); \
149 AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, VERR_INVALID_MAGIC); \
150 } while (0)
151
152
153/** Gets and validates a test instance.
154 * If the handle is nil, we will try retrive it from the test TLS entry.
155 */
156#define RTTEST_GET_VALID_RETURN_RC(pTest, rc) \
157 do { \
158 if (pTest == NIL_RTTEST) \
159 pTest = (PRTTESTINT)RTTlsGet(g_iTestTls); \
160 AssertPtrReturn(pTest, (rc)); \
161 AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, (rc)); \
162 } while (0)
163
164
165/*******************************************************************************
166* Internal Functions *
167*******************************************************************************/
168static void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem);
169static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...);
170
171
172/*******************************************************************************
173* Global Variables *
174*******************************************************************************/
175/** For serializing TLS init. */
176static RTONCE g_TestInitOnce = RTONCE_INITIALIZER;
177/** Our TLS entry. */
178static RTTLS g_iTestTls = NIL_RTTLS;
179
180
181
182/**
183 * Init TLS index once.
184 *
185 * @returns IPRT status code.
186 * @param pvUser1 Ignored.
187 * @param pvUser2 Ignored.
188 */
189static DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser1, void *pvUser2)
190{
191 NOREF(pvUser1);
192 NOREF(pvUser2);
193 return RTTlsAllocEx(&g_iTestTls, NULL);
194}
195
196
197
198/**
199 * Creates a test instance.
200 *
201 * @returns IPRT status code.
202 * @param pszTest The test name.
203 * @param phTest Where to store the test instance handle.
204 */
205RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
206{
207 /*
208 * Global init.
209 */
210 int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL, NULL);
211 if (RT_FAILURE(rc))
212 return rc;
213
214 /*
215 * Create the instance.
216 */
217 PRTTESTINT pTest = (PRTTESTINT)RTMemAllocZ(sizeof(*pTest));
218 if (!pTest)
219 return VERR_NO_MEMORY;
220 pTest->u32Magic = RTTESTINT_MAGIC;
221 pTest->pszTest = RTStrDup(pszTest);
222 pTest->cchTest = strlen(pszTest);
223 pTest->cbGuard = PAGE_SIZE * 7;
224 pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
225
226 pTest->pOutStrm = g_pStdOut;
227 pTest->fNewLine = true;
228
229 pTest->pGuardedMem = NULL;
230
231 pTest->pszSubTest = NULL;
232 pTest->cchSubTest = 0;
233 pTest->fSubTestReported = true;
234 pTest->cSubTestAtErrors = 0;
235 pTest->cSubTests = 0;
236 pTest->cSubTestsFailed = 0;
237
238 rc = RTCritSectInit(&pTest->Lock);
239 if (RT_SUCCESS(rc))
240 {
241 rc = RTCritSectInit(&pTest->OutputLock);
242 if (RT_SUCCESS(rc))
243 {
244
245 /*
246 * Associate it with our TLS entry unless there is already
247 * an instance there.
248 */
249 if (!RTTlsGet(g_iTestTls))
250 rc = RTTlsSet(g_iTestTls, pTest);
251 if (RT_SUCCESS(rc))
252 {
253 /*
254 * Finally, pick up overrides from the environment.
255 */
256 char szMaxLevel[80];
257 rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szMaxLevel, sizeof(szMaxLevel), NULL);
258 if (RT_SUCCESS(rc))
259 {
260 char *pszMaxLevel = RTStrStrip(szMaxLevel);
261 if (!strcmp(pszMaxLevel, "all"))
262 pTest->enmMaxLevel = RTTESTLVL_DEBUG;
263 if (!strcmp(pszMaxLevel, "quiet"))
264 pTest->enmMaxLevel = RTTESTLVL_FAILURE;
265 else if (!strcmp(pszMaxLevel, "debug"))
266 pTest->enmMaxLevel = RTTESTLVL_DEBUG;
267 else if (!strcmp(pszMaxLevel, "info"))
268 pTest->enmMaxLevel = RTTESTLVL_INFO;
269 else if (!strcmp(pszMaxLevel, "sub_test"))
270 pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
271 else if (!strcmp(pszMaxLevel, "failure"))
272 pTest->enmMaxLevel = RTTESTLVL_FAILURE;
273 }
274
275 *phTest = pTest;
276 return VINF_SUCCESS;
277 }
278
279 /* bail out. */
280 RTCritSectDelete(&pTest->OutputLock);
281 }
282 RTCritSectDelete(&pTest->Lock);
283 }
284 pTest->u32Magic = 0;
285 RTStrFree((char *)pTest->pszTest);
286 RTMemFree(pTest);
287 return rc;
288}
289
290
291RTR3DECL(int) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest)
292{
293 int rc = RTR3Init();
294 if (RT_FAILURE(rc))
295 {
296 RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3Init failed with rc=%Rrc\n", pszTest, rc);
297 return 16;
298 }
299 rc = RTTestCreate(pszTest, phTest);
300 if (RT_FAILURE(rc))
301 {
302 RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc);
303 return 17;
304 }
305 return 0;
306}
307
308
309/**
310 * Destroys a test instance previously created by RTTestCreate.
311 *
312 * @returns IPRT status code.
313 * @param hTest The test handle. NIL_RTTEST is ignored.
314 */
315RTR3DECL(int) RTTestDestroy(RTTEST hTest)
316{
317 /*
318 * Validate
319 */
320 if (hTest == NIL_RTTEST)
321 return VINF_SUCCESS;
322 RTTESTINT *pTest = hTest;
323 RTTEST_VALID_RETURN(pTest);
324
325 /*
326 * Make sure we end with a new line.
327 */
328 if (!pTest->fNewLine)
329 rtTestPrintf(pTest, "\n");
330
331 /*
332 * Clean up.
333 */
334 if ((RTTESTINT *)RTTlsGet(g_iTestTls) == pTest)
335 RTTlsSet(g_iTestTls, NULL);
336
337 ASMAtomicWriteU32(&pTest->u32Magic, ~RTTESTINT_MAGIC);
338 RTCritSectDelete(&pTest->Lock);
339 RTCritSectDelete(&pTest->OutputLock);
340
341 /* free guarded memory. */
342 PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem;
343 pTest->pGuardedMem = NULL;
344 while (pMem)
345 {
346 PRTTESTGUARDEDMEM pFree = pMem;
347 pMem = pMem->pNext;
348 rtTestGuardedFreeOne(pFree);
349 }
350
351 RTStrFree((char *)pTest->pszSubTest);
352 pTest->pszSubTest = NULL;
353 RTStrFree((char *)pTest->pszTest);
354 pTest->pszTest = NULL;
355 RTMemFree(pTest);
356 return VINF_SUCCESS;
357}
358
359
360/**
361 * Changes the default test instance for the calling thread.
362 *
363 * @returns IPRT status code.
364 *
365 * @param hNewDefaultTest The new default test. NIL_RTTEST is fine.
366 * @param phOldTest Where to store the old test handle. Optional.
367 */
368RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest)
369{
370 if (phOldTest)
371 *phOldTest = (RTTEST)RTTlsGet(g_iTestTls);
372 return RTTlsSet(g_iTestTls, hNewDefaultTest);
373}
374
375
376/**
377 * Allocate a block of guarded memory.
378 *
379 * @returns IPRT status code.
380 * @param hTest The test handle. If NIL_RTTEST we'll use the one
381 * associated with the calling thread.
382 * @param cb The amount of memory to allocate.
383 * @param cbAlign The alignment of the returned block.
384 * @param fHead Head or tail optimized guard.
385 * @param ppvUser Where to return the pointer to the block.
386 */
387RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser)
388{
389 PRTTESTINT pTest = hTest;
390 RTTEST_GET_VALID_RETURN(pTest);
391 if (cbAlign == 0)
392 cbAlign = 1;
393 AssertReturn(cbAlign <= PAGE_SIZE, VERR_INVALID_PARAMETER);
394 AssertReturn(cbAlign == (UINT32_C(1) << (ASMBitFirstSetU32(cbAlign) - 1)), VERR_INVALID_PARAMETER);
395
396 /*
397 * Allocate the record and block and initialize them.
398 */
399 int rc = VERR_NO_MEMORY;
400 PRTTESTGUARDEDMEM pMem = (PRTTESTGUARDEDMEM)RTMemAlloc(sizeof(*pMem));
401 if (RT_LIKELY(pMem))
402 {
403 size_t const cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
404 pMem->aGuards[0].cb = pMem->aGuards[1].cb = pTest->cbGuard;
405 pMem->cbAlloc = pMem->aGuards[0].cb + pMem->aGuards[1].cb + cbAligned;
406 pMem->pvAlloc = RTMemPageAlloc(pMem->cbAlloc);
407 if (pMem->pvAlloc)
408 {
409 pMem->aGuards[0].pv = pMem->pvAlloc;
410 pMem->pvUser = (uint8_t *)pMem->pvAlloc + pMem->aGuards[0].cb;
411 pMem->aGuards[1].pv = (uint8_t *)pMem->pvUser + cbAligned;
412 if (!fHead)
413 {
414 size_t off = cb & PAGE_OFFSET_MASK;
415 if (off)
416 {
417 off = PAGE_SIZE - RT_ALIGN_Z(off, cbAlign);
418 pMem->pvUser = (uint8_t *)pMem->pvUser + off;
419 }
420 }
421
422 /*
423 * Set up the guards and link the record.
424 */
425 ASMMemFill32(pMem->aGuards[0].pv, pMem->aGuards[0].cb, 0xdeadbeef);
426 ASMMemFill32(pMem->aGuards[1].pv, pMem->aGuards[1].cb, 0xdeadbeef);
427 rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_NONE);
428 if (RT_SUCCESS(rc))
429 {
430 rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_NONE);
431 if (RT_SUCCESS(rc))
432 {
433 *ppvUser = pMem->pvUser;
434
435 RTCritSectEnter(&pTest->Lock);
436 pMem->pNext = pTest->pGuardedMem;
437 pTest->pGuardedMem = pMem;
438 RTCritSectLeave(&pTest->Lock);
439
440 return VINF_SUCCESS;
441 }
442
443 RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ);
444 }
445
446 RTMemPageFree(pMem->pvAlloc);
447 }
448 RTMemFree(pMem);
449 }
450 return rc;
451}
452
453
454/**
455 * Allocates a block of guarded memory where the guarded is immediately after
456 * the user memory.
457 *
458 * @returns Pointer to the allocated memory. NULL on failure.
459 * @param hTest The test handle. If NIL_RTTEST we'll use the one
460 * associated with the calling thread.
461 * @param cb The amount of memory to allocate.
462 */
463RTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb)
464{
465 void *pvUser;
466 int rc = RTTestGuardedAlloc(hTest, cb, 1, false /*fHead*/, &pvUser);
467 if (RT_SUCCESS(rc))
468 return pvUser;
469 return NULL;
470}
471
472
473/**
474 * Allocates a block of guarded memory where the guarded is right in front of
475 * the user memory.
476 *
477 * @returns Pointer to the allocated memory. NULL on failure.
478 * @param hTest The test handle. If NIL_RTTEST we'll use the one
479 * associated with the calling thread.
480 * @param cb The amount of memory to allocate.
481 */
482RTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb)
483{
484 void *pvUser;
485 int rc = RTTestGuardedAlloc(hTest, cb, 1, true /*fHead*/, &pvUser);
486 if (RT_SUCCESS(rc))
487 return pvUser;
488 return NULL;
489}
490
491
492/**
493 * Frees one block of guarded memory.
494 *
495 * The caller is responsible for unlinking it.
496 *
497 * @param pMem The memory record.
498 */
499static void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem)
500{
501 int rc;
502 rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
503 rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
504 RTMemPageFree(pMem->pvAlloc);
505 RTMemFree(pMem);
506}
507
508
509/**
510 * Frees a block of guarded memory.
511 *
512 * @returns IPRT status code.
513 * @param hTest The test handle. If NIL_RTTEST we'll use the one
514 * associated with the calling thread.
515 * @param pv The memory. NULL is ignored.
516 */
517RTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv)
518{
519 PRTTESTINT pTest = hTest;
520 RTTEST_GET_VALID_RETURN(pTest);
521 if (!pv)
522 return VINF_SUCCESS;
523
524 /*
525 * Find it.
526 */
527 int rc = VERR_INVALID_POINTER;
528 PRTTESTGUARDEDMEM pPrev = NULL;
529
530 RTCritSectEnter(&pTest->Lock);
531 for (PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem; pMem; pMem = pMem->pNext)
532 {
533 if (pMem->pvUser == pv)
534 {
535 if (pPrev)
536 pPrev->pNext = pMem->pNext;
537 else
538 pTest->pGuardedMem = pMem->pNext;
539 rtTestGuardedFreeOne(pMem);
540 rc = VINF_SUCCESS;
541 break;
542 }
543 pPrev = pMem;
544 }
545 RTCritSectLeave(&pTest->Lock);
546
547 return VINF_SUCCESS;
548}
549
550
551/**
552 * Output callback.
553 *
554 * @returns number of bytes written.
555 * @param pvArg User argument.
556 * @param pachChars Pointer to an array of utf-8 characters.
557 * @param cbChars Number of bytes in the character array pointed to by pachChars.
558 */
559static DECLCALLBACK(size_t) rtTestPrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
560{
561 size_t cch = 0;
562 PRTTESTINT pTest = (PRTTESTINT)pvArg;
563 if (cbChars)
564 {
565 do
566 {
567 /* insert prefix if at a newline. */
568 if (pTest->fNewLine)
569 {
570 RTStrmWrite(pTest->pOutStrm, pTest->pszTest, pTest->cchTest);
571 RTStrmWrite(pTest->pOutStrm, ": ", 2);
572 cch += 2 + pTest->cchTest;
573 }
574
575 /* look for newline and write the stuff. */
576 const char *pchEnd = (const char *)memchr(pachChars, '\n', cbChars);
577 if (!pchEnd)
578 {
579 pTest->fNewLine = false;
580 RTStrmWrite(pTest->pOutStrm, pachChars, cbChars);
581 cch += cbChars;
582 break;
583 }
584
585 pTest->fNewLine = true;
586 size_t const cchPart = pchEnd - pachChars + 1;
587 RTStrmWrite(pTest->pOutStrm, pachChars, cchPart);
588 cch += cchPart;
589 pachChars += cchPart;
590 cbChars -= cchPart;
591 } while (cbChars);
592 }
593 else
594 RTStrmFlush(pTest->pOutStrm);
595 return cch;
596}
597
598
599/**
600 * Internal output worker.
601 *
602 * Caller takes the lock.
603 *
604 * @returns Number of chars printed.
605 * @param pTest The test instance.
606 * @param pszFormat The message.
607 * @param va The arguments.
608 */
609static int rtTestPrintfV(PRTTESTINT pTest, const char *pszFormat, va_list va)
610{
611 return (int)RTStrFormatV(rtTestPrintfOutput, pTest, NULL, NULL, pszFormat, va);
612}
613
614
615/**
616 * Internal output worker.
617 *
618 * Caller takes the lock.
619 *
620 * @returns Number of chars printed.
621 * @param pTest The test instance.
622 * @param pszFormat The message.
623 * @param ... The arguments.
624 */
625static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...)
626{
627 va_list va;
628
629 va_start(va, pszFormat);
630 int cch = rtTestPrintfV(pTest, pszFormat, va);
631 va_end(va);
632
633 return cch;
634}
635
636
637/**
638 * Test vprintf making sure the output starts on a new line.
639 *
640 * @returns Number of chars printed.
641 * @param hTest The test handle. If NIL_RTTEST we'll use the one
642 * associated with the calling thread.
643 * @param enmLevel Message importance level.
644 * @param pszFormat The message.
645 * @param va Arguments.
646 */
647RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
648{
649 PRTTESTINT pTest = hTest;
650 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
651
652 RTCritSectEnter(&pTest->OutputLock);
653
654 int cch = 0;
655 if (enmLevel <= pTest->enmMaxLevel)
656 {
657 if (!pTest->fNewLine)
658 cch += rtTestPrintf(pTest, "\n");
659 cch += rtTestPrintfV(pTest, pszFormat, va);
660 }
661
662 RTCritSectLeave(&pTest->OutputLock);
663
664 return cch;
665}
666
667
668/**
669 * Test printf making sure the output starts on a new line.
670 *
671 * @returns Number of chars printed.
672 * @param hTest The test handle. If NIL_RTTEST we'll use the one
673 * associated with the calling thread.
674 * @param enmLevel Message importance level.
675 * @param pszFormat The message.
676 * @param ... Arguments.
677 */
678RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
679{
680 va_list va;
681
682 va_start(va, pszFormat);
683 int cch = RTTestPrintfNlV(hTest, enmLevel, pszFormat, va);
684 va_end(va);
685
686 return cch;
687}
688
689
690/**
691 * Test vprintf, makes sure lines are prefixed and so forth.
692 *
693 * @returns Number of chars printed.
694 * @param hTest The test handle. If NIL_RTTEST we'll use the one
695 * associated with the calling thread.
696 * @param enmLevel Message importance level.
697 * @param pszFormat The message.
698 * @param va Arguments.
699 */
700RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
701{
702 PRTTESTINT pTest = hTest;
703 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
704
705 RTCritSectEnter(&pTest->OutputLock);
706 int cch = 0;
707 if (enmLevel <= pTest->enmMaxLevel)
708 cch += rtTestPrintfV(pTest, pszFormat, va);
709 RTCritSectLeave(&pTest->OutputLock);
710
711 return cch;
712}
713
714
715/**
716 * Test printf, makes sure lines are prefixed and so forth.
717 *
718 * @returns Number of chars printed.
719 * @param hTest The test handle. If NIL_RTTEST we'll use the one
720 * associated with the calling thread.
721 * @param enmLevel Message importance level.
722 * @param pszFormat The message.
723 * @param ... Arguments.
724 */
725RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
726{
727 va_list va;
728
729 va_start(va, pszFormat);
730 int cch = RTTestPrintfV(hTest, enmLevel, pszFormat, va);
731 va_end(va);
732
733 return cch;
734}
735
736
737/**
738 * Prints the test banner.
739 *
740 * @returns Number of chars printed.
741 * @param hTest The test handle. If NIL_RTTEST we'll use the one
742 * associated with the calling thread.
743 */
744RTR3DECL(int) RTTestBanner(RTTEST hTest)
745{
746 return RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "TESTING...\n");
747}
748
749
750/**
751 * Prints the result of a sub-test if necessary.
752 *
753 * @returns Number of chars printed.
754 * @param pTest The test instance.
755 * @remarks Caller own the test Lock.
756 */
757static int rtTestSubTestReport(PRTTESTINT pTest)
758{
759 int cch = 0;
760 if ( !pTest->fSubTestReported
761 && pTest->pszSubTest)
762 {
763 pTest->fSubTestReported = true;
764 uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
765 if (!cErrors)
766 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest);
767 else
768 {
769 pTest->cSubTestsFailed++;
770 cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: FAILED (%u errors)\n",
771 pTest->pszSubTest, cErrors);
772 }
773 }
774 return cch;
775}
776
777
778/**
779 * RTTestSub and RTTestSubDone worker that cleans up the current (if any)
780 * sub test.
781 *
782 * @returns Number of chars printed.
783 * @param pTest The test instance.
784 * @remarks Caller own the test Lock.
785 */
786static int rtTestSubCleanup(PRTTESTINT pTest)
787{
788 int cch = 0;
789 if (pTest->pszSubTest)
790 {
791 cch += rtTestSubTestReport(pTest);
792
793 RTStrFree((char *)pTest->pszSubTest);
794 pTest->pszSubTest = NULL;
795 pTest->fSubTestReported = true;
796 }
797 return cch;
798}
799
800
801/**
802 * Summaries the test, destroys the test instance and return an exit code.
803 *
804 * @returns Test program exit code.
805 * @param hTest The test handle. If NIL_RTTEST we'll use the one
806 * associated with the calling thread.
807 */
808RTR3DECL(int) RTTestSummaryAndDestroy(RTTEST hTest)
809{
810 PRTTESTINT pTest = hTest;
811 RTTEST_GET_VALID_RETURN_RC(pTest, 2);
812
813 RTCritSectEnter(&pTest->Lock);
814 rtTestSubTestReport(pTest);
815 RTCritSectLeave(&pTest->Lock);
816
817 int rc;
818 if (!pTest->cErrors)
819 {
820 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SUCCESS\n", pTest->cErrors);
821 rc = 0;
822 }
823 else
824 {
825 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
826 rc = 1;
827 }
828
829 RTTestDestroy(pTest);
830 return rc;
831}
832
833
834RTR3DECL(int) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReason, va_list va)
835{
836 PRTTESTINT pTest = hTest;
837 RTTEST_GET_VALID_RETURN_RC(pTest, 2);
838
839 RTCritSectEnter(&pTest->Lock);
840 rtTestSubTestReport(pTest);
841 RTCritSectLeave(&pTest->Lock);
842
843 int rc;
844 if (!pTest->cErrors)
845 {
846 if (pszReason)
847 RTTestPrintfNlV(hTest, RTTESTLVL_FAILURE, pszReason, va);
848 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SKIPPED\n", pTest->cErrors);
849 rc = 2;
850 }
851 else
852 {
853 RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
854 rc = 1;
855 }
856
857 RTTestDestroy(pTest);
858 return rc;
859}
860
861
862RTR3DECL(int) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReason, ...)
863{
864 va_list va;
865 va_start(va, pszReason);
866 int rc = RTTestSkipAndDestroyV(hTest, pszReason, va);
867 va_end(va);
868 return rc;
869}
870
871
872/**
873 * Starts a sub-test.
874 *
875 * This will perform an implicit RTTestSubDone() call if that has not been done
876 * since the last RTTestSub call.
877 *
878 * @returns Number of chars printed.
879 * @param hTest The test handle. If NIL_RTTEST we'll use the one
880 * associated with the calling thread.
881 * @param pszSubTest The sub-test name
882 */
883RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest)
884{
885 PRTTESTINT pTest = hTest;
886 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
887
888 RTCritSectEnter(&pTest->Lock);
889
890 /* Cleanup, reporting if necessary previous sub test. */
891 rtTestSubCleanup(pTest);
892
893 /* Start new sub test. */
894 pTest->cSubTests++;
895 pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors);
896 pTest->pszSubTest = RTStrDup(pszSubTest);
897 pTest->cchSubTest = strlen(pszSubTest);
898 pTest->fSubTestReported = false;
899
900 int cch = 0;
901 if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
902 cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
903
904 RTCritSectLeave(&pTest->Lock);
905
906 return cch;
907}
908
909
910/**
911 * Format string version of RTTestSub.
912 *
913 * See RTTestSub for details.
914 *
915 * @returns Number of chars printed.
916 * @param hTest The test handle. If NIL_RTTEST we'll use the one
917 * associated with the calling thread.
918 * @param pszSubTestFmt The sub-test name format string.
919 * @param ... Arguments.
920 */
921RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...)
922{
923 va_list va;
924 va_start(va, pszSubTestFmt);
925 int cch = RTTestSubV(hTest, pszSubTestFmt, va);
926 va_end(va);
927 return cch;
928}
929
930
931/**
932 * Format string version of RTTestSub.
933 *
934 * See RTTestSub for details.
935 *
936 * @returns Number of chars printed.
937 * @param hTest The test handle. If NIL_RTTEST we'll use the one
938 * associated with the calling thread.
939 * @param pszSubTestFmt The sub-test name format string.
940 * @param ... Arguments.
941 */
942RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va)
943{
944 char *pszSubTest;
945 RTStrAPrintfV(&pszSubTest, pszSubTestFmt, va);
946 if (pszSubTest)
947 {
948 int cch = RTTestSub(hTest, pszSubTest);
949 RTStrFree(pszSubTest);
950 return cch;
951 }
952 return 0;
953}
954
955
956/**
957 * Completes a sub-test.
958 *
959 * @returns Number of chars printed.
960 * @param hTest The test handle. If NIL_RTTEST we'll use the one
961 * associated with the calling thread.
962 */
963RTR3DECL(int) RTTestSubDone(RTTEST hTest)
964{
965 PRTTESTINT pTest = hTest;
966 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
967
968 RTCritSectEnter(&pTest->Lock);
969 int cch = rtTestSubCleanup(pTest);
970 RTCritSectLeave(&pTest->Lock);
971
972 return cch;
973}
974
975/**
976 * Prints an extended PASSED message, optional.
977 *
978 * This does not conclude the sub-test, it could be used to report the passing
979 * of a sub-sub-to-the-power-of-N-test.
980 *
981 * @returns IPRT status code.
982 * @param hTest The test handle. If NIL_RTTEST we'll use the one
983 * associated with the calling thread.
984 * @param pszFormat The message. No trailing newline.
985 * @param va The arguments.
986 */
987RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
988{
989 PRTTESTINT pTest = hTest;
990 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
991
992 int cch = 0;
993 if (pTest->enmMaxLevel >= RTTESTLVL_INFO)
994 {
995 va_list va2;
996 va_copy(va2, va);
997
998 RTCritSectEnter(&pTest->OutputLock);
999 cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
1000 RTCritSectLeave(&pTest->OutputLock);
1001
1002 va_end(va2);
1003 }
1004
1005 return cch;
1006}
1007
1008
1009/**
1010 * Prints an extended PASSED message, optional.
1011 *
1012 * This does not conclude the sub-test, it could be used to report the passing
1013 * of a sub-sub-to-the-power-of-N-test.
1014 *
1015 * @returns IPRT status code.
1016 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1017 * associated with the calling thread.
1018 * @param pszFormat The message. No trailing newline.
1019 * @param ... The arguments.
1020 */
1021RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...)
1022{
1023 va_list va;
1024
1025 va_start(va, pszFormat);
1026 int cch = RTTestPassedV(hTest, pszFormat, va);
1027 va_end(va);
1028
1029 return cch;
1030}
1031
1032
1033/**
1034 * Increments the error counter.
1035 *
1036 * @returns IPRT status code.
1037 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1038 * associated with the calling thread.
1039 */
1040RTR3DECL(int) RTTestErrorInc(RTTEST hTest)
1041{
1042 PRTTESTINT pTest = hTest;
1043 RTTEST_GET_VALID_RETURN(pTest);
1044
1045 ASMAtomicIncU32(&pTest->cErrors);
1046
1047 return VINF_SUCCESS;
1048}
1049
1050
1051/**
1052 * Increments the error counter and prints a failure message.
1053 *
1054 * @returns IPRT status code.
1055 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1056 * associated with the calling thread.
1057 * @param pszFormat The message. No trailing newline.
1058 * @param va The arguments.
1059 */
1060RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va)
1061{
1062 PRTTESTINT pTest = hTest;
1063 RTTEST_GET_VALID_RETURN_RC(pTest, -1);
1064
1065 RTTestErrorInc(pTest);
1066
1067 int cch = 0;
1068 if (pTest->enmMaxLevel >= RTTESTLVL_FAILURE)
1069 {
1070 va_list va2;
1071 va_copy(va2, va);
1072
1073 const char *pszEnd = strchr(pszFormat, '\0');
1074 bool fHasNewLine = pszFormat != pszEnd
1075 && pszEnd[-1] == '\n';
1076
1077 RTCritSectEnter(&pTest->OutputLock);
1078 cch += rtTestPrintf(pTest, fHasNewLine ? "%N" : "%N\n", pszFormat, &va2);
1079 RTCritSectLeave(&pTest->OutputLock);
1080
1081 va_end(va2);
1082 }
1083
1084 return cch;
1085}
1086
1087
1088/**
1089 * Increments the error counter and prints a failure message.
1090 *
1091 * @returns IPRT status code.
1092 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1093 * associated with the calling thread.
1094 * @param pszFormat The message. No trailing newline.
1095 * @param ... The arguments.
1096 */
1097RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...)
1098{
1099 va_list va;
1100
1101 va_start(va, pszFormat);
1102 int cch = RTTestFailedV(hTest, pszFormat, va);
1103 va_end(va);
1104
1105 return cch;
1106}
1107
1108
1109/**
1110 * Same as RTTestPrintfV with RTTESTLVL_FAILURE.
1111 *
1112 * @returns Number of chars printed.
1113 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1114 * associated with the calling thread.
1115 * @param enmLevel Message importance level.
1116 * @param pszFormat The message.
1117 * @param va Arguments.
1118 */
1119RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va)
1120{
1121 return RTTestPrintfV(hTest, RTTESTLVL_FAILURE, pszFormat, va);
1122}
1123
1124
1125/**
1126 * Same as RTTestPrintf with RTTESTLVL_FAILURE.
1127 *
1128 * @returns Number of chars printed.
1129 * @param hTest The test handle. If NIL_RTTEST we'll use the one
1130 * associated with the calling thread.
1131 * @param enmLevel Message importance level.
1132 * @param pszFormat The message.
1133 * @param ... Arguments.
1134 */
1135RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...)
1136{
1137 va_list va;
1138 va_start(va, pszFormat);
1139 int cch = RTTestFailureDetailsV(hTest, pszFormat, va);
1140 va_end(va);
1141 return cch;
1142}
1143
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