VirtualBox

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

Last change on this file since 20008 was 19952, checked in by vboxsync, 16 years ago

RTTest: More macros. Made RTTestFailure check for trailing new line to avoid getting an extra blank line.

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