VirtualBox

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

最後變更 在這個檔案從20573是 20573,由 vboxsync 提交於 16 年 前

iprt/test.h: Added RTTestSetDefault.

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

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