VirtualBox

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

Last change on this file since 18784 was 18569, checked in by vboxsync, 16 years ago

RTTest: sub tests, more typical reporting of those.

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