Index: /trunk/include/iprt/test.h
===================================================================
--- /trunk/include/iprt/test.h	(revision 18568)
+++ /trunk/include/iprt/test.h	(revision 18569)
@@ -52,4 +52,25 @@
 #define NIL_RTTEST  ((RTTEST)0)
 
+/**
+ * Test message importance level.
+ */
+typedef enum RTTESTLVL
+{
+    /** Invalid 0. */
+    RTTESTLVL_INVALID = 0,
+    /** Message should always be printed. */
+    RTTESTLVL_ALWAYS,
+    /** Failure message. */
+    RTTESTLVL_FAILURE,
+    /** Sub-test banner. */
+    RTTESTLVL_SUB_TEST,
+    /** Info message. */
+    RTTESTLVL_INFO,
+    /** Debug message. */
+    RTTESTLVL_DEBUG,
+    /** The last (invalid). */
+    RTTESTLVL_END
+} RTTESTLVL;
+
 
 /**
@@ -121,8 +142,9 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   va          Arguments.
  */
-RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, const char *pszFormat, va_list va);
+RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va);
 
 /**
@@ -132,8 +154,9 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   ...         Arguments.
  */
-RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, const char *pszFormat, ...);
+RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...);
 
 /**
@@ -143,8 +166,9 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   va          Arguments.
  */
-RTR3DECL(int) RTTestPrintfV(RTTEST hTest, const char *pszFormat, va_list va);
+RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va);
 
 /**
@@ -154,8 +178,9 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   ...         Arguments.
  */
-RTR3DECL(int) RTTestPrintf(RTTEST hTest, const char *pszFormat, ...);
+RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...);
 
 /**
@@ -176,4 +201,26 @@
  */
 RTR3DECL(int) RTTestSummaryAndDestroy(RTTEST hTest);
+
+/**
+ * Starts a sub-test.
+ *
+ * This will perform an implicit RTTestSubDone() call if that has not been done
+ * since the last RTTestSub call.
+ *
+ * @returns Number of chars printed.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ * @param   pszSubTest  The sub-test name
+ */
+RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest);
+
+/**
+ * Completes a sub-test.
+ *
+ * @returns Number of chars printed.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ */
+RTR3DECL(int) RTTestSubDone(RTTEST hTest);
 
 /**
@@ -220,4 +267,50 @@
     do { if (!(expr)) { RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); } } while (0)
 
+/** @def RTTEST_CHECK_MSG
+ * Check whether a boolean expression holds true.
+ *
+ * If the expression is false, call RTTestFailed giving the line number and expression.
+ *
+ * @param   hTest           The test handle.
+ * @param   expr            The expression to evaluate.
+ * @param   TestPrintfArgs  Argument list for RTTestPrintf, including
+ *                          parenthesis.
+ */
+#define RTTEST_CHECK_MSG(hTest, expr, TestPrintfArgs) \
+    do { if (!(expr)) { \
+            RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \
+            RTTestPrintf TestPrintfArgs; \
+         } \
+    } while (0)
+
+
+/**
+ * Prints an extended PASSED message, optional.
+ *
+ * This does not conclude the sub-test, it could be used to report the passing
+ * of a sub-sub-to-the-power-of-N-test.
+ *
+ * @returns IPRT status code.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ * @param   pszFormat   The message. No trailing newline.
+ * @param   va          The arguments.
+ */
+RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va);
+
+/**
+ * Prints an extended PASSED message, optional.
+ *
+ * This does not conclude the sub-test, it could be used to report the passing
+ * of a sub-sub-to-the-power-of-N-test.
+ *
+ * @returns IPRT status code.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ * @param   pszFormat   The message. No trailing newline.
+ * @param   ...         The arguments.
+ */
+RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...);
+
 
 /** @}  */
Index: /trunk/src/VBox/Runtime/r3/test.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/test.cpp	(revision 18568)
+++ /trunk/src/VBox/Runtime/r3/test.cpp	(revision 18569)
@@ -86,12 +86,10 @@
     const char         *pszTest;
     /** The length of the test name.  */
-    unsigned            cchTest;
+    size_t              cchTest;
     /** The size of a guard. Multiple of PAGE_SIZE. */
     uint32_t            cbGuard;
-
-    /** Critical section seralizing access to the members following it. */
-    RTCRITSECT          Lock;
-    /** The list of guarded memory allocations. */
-    PRTTESTGUARDEDMEM   pGuardedMem;
+    /** The verbosity level. */
+    RTTESTLVL           enmMaxLevel;
+
 
     /** Critical section seralizing output. */
@@ -101,4 +99,25 @@
     /** Whether we're currently at a newline. */
     bool                fNewLine;
+
+
+    /** Critical section seralizing access to the members following it. */
+    RTCRITSECT          Lock;
+
+    /** The list of guarded memory allocations. */
+    PRTTESTGUARDEDMEM   pGuardedMem;
+
+    /** The current sub-test. */
+    const char         *pszSubTest;
+    /** The lenght of the sub-test name. */
+    size_t              cchSubTest;
+    /** Whether we've reported the sub-test result or not. */
+    bool                fSubTestReported;
+    /** The start error count of the current subtest. */
+    uint32_t            cSubTestAtErrors;
+
+    /** The number of sub tests. */
+    uint32_t            cSubTests;
+    /** The number of sub tests that failed. */
+    uint32_t            cSubTestsFailed;
 
 } RTTESTINT;
@@ -195,10 +214,21 @@
     if (!pTest)
         return VERR_NO_MEMORY;
-    pTest->u32Magic = RTTESTINT_MAGIC;
-    pTest->cbGuard  = PAGE_SIZE * 7;
-    pTest->pszTest  = RTStrDup(pszTest);
-    pTest->cchTest  = (unsigned)strlen(pszTest);
-    pTest->pOutStrm = g_pStdOut;
-    pTest->fNewLine = true;
+    pTest->u32Magic         = RTTESTINT_MAGIC;
+    pTest->pszTest          = RTStrDup(pszTest);
+    pTest->cchTest          = strlen(pszTest);
+    pTest->cbGuard          = PAGE_SIZE * 7;
+    pTest->enmMaxLevel      = RTTESTLVL_SUB_TEST;
+
+    pTest->pOutStrm         = g_pStdOut;
+    pTest->fNewLine         = true;
+
+    pTest->pGuardedMem      = NULL;
+
+    pTest->pszSubTest       = NULL;
+    pTest->cchSubTest       = 0;
+    pTest->fSubTestReported = true;
+    pTest->cSubTestAtErrors = 0;
+    pTest->cSubTests        = 0;
+    pTest->cSubTestsFailed  = 0;
 
     rc = RTCritSectInit(&pTest->Lock);
@@ -269,4 +299,6 @@
     }
 
+    RTStrFree((char *)pTest->pszSubTest);
+    pTest->pszSubTest = NULL;
     RTStrFree((char *)pTest->pszTest);
     pTest->pszTest = NULL;
@@ -544,8 +576,9 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   va          Arguments.
  */
-RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, const char *pszFormat, va_list va)
+RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
 {
     PRTTESTINT pTest = hTest;
@@ -555,7 +588,10 @@
 
     int cch = 0;
-    if (!pTest->fNewLine)
-        cch += rtTestPrintf(pTest, "\n");
-    cch += rtTestPrintfV(pTest, pszFormat, va);
+    if (enmLevel <= pTest->enmMaxLevel)
+    {
+        if (!pTest->fNewLine)
+            cch += rtTestPrintf(pTest, "\n");
+        cch += rtTestPrintfV(pTest, pszFormat, va);
+    }
 
     RTCritSectLeave(&pTest->OutputLock);
@@ -571,13 +607,14 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   ...         Arguments.
  */
-RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, const char *pszFormat, ...)
+RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
 {
     va_list va;
 
     va_start(va, pszFormat);
-    int cch = RTTestPrintfNlV(hTest, pszFormat, va);
+    int cch = RTTestPrintfNlV(hTest, enmLevel, pszFormat, va);
     va_end(va);
 
@@ -592,8 +629,9 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   va          Arguments.
  */
-RTR3DECL(int) RTTestPrintfV(RTTEST hTest, const char *pszFormat, va_list va)
+RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
 {
     PRTTESTINT pTest = hTest;
@@ -601,5 +639,7 @@
 
     RTCritSectEnter(&pTest->OutputLock);
-    int cch = rtTestPrintfV(pTest, pszFormat, va);
+    int cch = 0;
+    if (enmLevel <= pTest->enmMaxLevel)
+        cch += rtTestPrintfV(pTest, pszFormat, va);
     RTCritSectLeave(&pTest->OutputLock);
 
@@ -614,13 +654,14 @@
  * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
  *                      associated with the calling thread.
+ * @param   enmLevel    Message importance level.
  * @param   pszFormat   The message.
  * @param   ...         Arguments.
  */
-RTR3DECL(int) RTTestPrintf(RTTEST hTest, const char *pszFormat, ...)
+RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
 {
     va_list va;
 
     va_start(va, pszFormat);
-    int cch = RTTestPrintfV(hTest, pszFormat, va);
+    int cch = RTTestPrintfV(hTest, enmLevel, pszFormat, va);
     va_end(va);
 
@@ -638,5 +679,56 @@
 RTR3DECL(int) RTTestBanner(RTTEST hTest)
 {
-    return RTTestPrintfNl(hTest, "TESTING...\n");
+    return RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "TESTING...\n");
+}
+
+
+/**
+ * Prints the result of a sub-test if necessary.
+ *
+ * @returns Number of chars printed.
+ * @param   pTest       The test instance.
+ * @remarks Caller own the test Lock.
+ */
+static int rtTestSubTestReport(PRTTESTINT pTest)
+{
+    int cch = 0;
+    if (    !pTest->fSubTestReported
+        &&  pTest->pszSubTest)
+    {
+        pTest->fSubTestReported = true;
+        uint32_t cErrors = ASMAtomicUoReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
+        if (!cErrors)
+            cch += RTTestPrintf(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest);
+        else
+        {
+            pTest->cSubTestsFailed++;
+            cch += RTTestPrintf(pTest, RTTESTLVL_SUB_TEST, "%-50s: FAILED (%u errors)\n",
+                                pTest->pszSubTest, cErrors);
+        }
+    }
+    return cch;
+}
+
+
+/**
+ * RTTestSub and RTTestSubDone worker that cleans up the current (if any)
+ * sub test.
+ *
+ * @returns Number of chars printed.
+ * @param   pTest       The test instance.
+ * @remarks Caller own the test Lock.
+ */
+static int rtTestSubCleanup(PRTTESTINT pTest)
+{
+    int cch = 0;
+    if (pTest->pszSubTest)
+    {
+        cch += rtTestSubTestReport(pTest);
+
+        RTStrFree((char *)pTest->pszSubTest);
+        pTest->pszSubTest = NULL;
+        pTest->fSubTestReported = true;
+    }
+    return cch;
 }
 
@@ -654,15 +746,20 @@
     RTTEST_GET_VALID_RETURN_RC(pTest, 2);
 
+    RTCritSectEnter(&pTest->Lock);
+    rtTestSubTestReport(pTest);
+    RTCritSectLeave(&pTest->Lock);
+
     int rc;
     if (!pTest->cErrors)
     {
-        RTTestPrintfNl(hTest, "SUCCESS\n", pTest->cErrors);
+        RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SUCCESS\n", pTest->cErrors);
         rc = 0;
     }
     else
     {
-        RTTestPrintfNl(hTest, "FAILURE - %u errors\n", pTest->cErrors);
+        RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
         rc = 1;
     }
+
 
     RTTestDestroy(pTest);
@@ -672,4 +769,62 @@
 
 /**
+ * Starts a sub-test.
+ *
+ * This will perform an implicit RTTestSubDone() call if that has not been done
+ * since the last RTTestSub call.
+ *
+ * @returns Number of chars printed.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ * @param   pszSubTest  The sub-test name
+ */
+RTR3DECL(int) RTTestSub(RTTEST hTest, const char *pszSubTest)
+{
+    PRTTESTINT pTest = hTest;
+    RTTEST_GET_VALID_RETURN_RC(pTest, -1);
+
+    RTCritSectEnter(&pTest->Lock);
+
+    /* Cleanup, reporting if necessary previous sub test. */
+    rtTestSubCleanup(pTest);
+
+    /* Start new sub test. */
+    pTest->cSubTests++;
+    pTest->cSubTestAtErrors = ASMAtomicUoReadU32(&pTest->cErrors);
+    pTest->pszSubTest = RTStrDup(pszSubTest);
+    pTest->cchSubTest = strlen(pszSubTest);
+    pTest->fSubTestReported = false;
+
+    int cch = 0;
+    if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
+        cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
+
+    RTCritSectLeave(&pTest->Lock);
+
+    return cch;
+}
+
+
+/**
+ * Completes a sub-test.
+ *
+ * @returns Number of chars printed.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ */
+RTR3DECL(int) RTTestSubDone(RTTEST hTest)
+{
+    PRTTESTINT pTest = hTest;
+    RTTEST_GET_VALID_RETURN_RC(pTest, -1);
+
+    RTCritSectEnter(&pTest->Lock);
+    int cch = rtTestSubCleanup(pTest);
+    RTCritSectLeave(&pTest->Lock);
+
+    return cch;
+}
+
+
+/**
  * Increments the error counter.
  *
@@ -682,5 +837,7 @@
     PRTTESTINT pTest = hTest;
     RTTEST_GET_VALID_RETURN(pTest);
+
     ASMAtomicIncU32(&pTest->cErrors);
+
     return VINF_SUCCESS;
 }
@@ -701,15 +858,18 @@
     RTTEST_GET_VALID_RETURN_RC(pTest, -1);
 
-    va_list va2;
-    va_copy(va2, va);
-
-    RTCritSectEnter(&pTest->OutputLock);
-    ASMAtomicIncU32(&pTest->cErrors);
-
-    int cch = rtTestPrintf(pTest, "FAILED - %N\n", pszFormat, &va2);
-
-    RTCritSectLeave(&pTest->OutputLock);
-
-    va_end(va2);
+    RTTestErrorInc(pTest);
+
+    int cch = 0;
+    if (pTest->enmMaxLevel >= RTTESTLVL_FAILURE)
+    {
+        va_list va2;
+        va_copy(va2, va);
+
+        RTCritSectEnter(&pTest->OutputLock);
+        cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
+        RTCritSectLeave(&pTest->OutputLock);
+
+        va_end(va2);
+    }
 
     return cch;
@@ -737,2 +897,60 @@
 }
 
+
+/**
+ * Prints an extended PASSED message, optional.
+ *
+ * This does not conclude the sub-test, it could be used to report the passing
+ * of a sub-sub-to-the-power-of-N-test.
+ *
+ * @returns IPRT status code.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ * @param   pszFormat   The message. No trailing newline.
+ * @param   va          The arguments.
+ */
+RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
+{
+    PRTTESTINT pTest = hTest;
+    RTTEST_GET_VALID_RETURN_RC(pTest, -1);
+
+    int cch = 0;
+    if (pTest->enmMaxLevel >= RTTESTLVL_INFO)
+    {
+        va_list va2;
+        va_copy(va2, va);
+
+        RTCritSectEnter(&pTest->OutputLock);
+        cch += rtTestPrintf(pTest, "%N\n", pszFormat, &va2);
+        RTCritSectLeave(&pTest->OutputLock);
+
+        va_end(va2);
+    }
+
+    return cch;
+}
+
+
+/**
+ * Prints an extended PASSED message, optional.
+ *
+ * This does not conclude the sub-test, it could be used to report the passing
+ * of a sub-sub-to-the-power-of-N-test.
+ *
+ * @returns IPRT status code.
+ * @param   hTest       The test handle. If NIL_RTTEST we'll use the one
+ *                      associated with the calling thread.
+ * @param   pszFormat   The message. No trailing newline.
+ * @param   ...         The arguments.
+ */
+RTR3DECL(int) RTTestPassed(RTTEST hTest, const char *pszFormat, ...)
+{
+    va_list va;
+
+    va_start(va, pszFormat);
+    int cch = RTTestPassedV(hTest, pszFormat, va);
+    va_end(va);
+
+    return cch;
+}
+
Index: /trunk/src/VBox/Runtime/testcase/tstBitOperations.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstBitOperations.cpp	(revision 18568)
+++ /trunk/src/VBox/Runtime/testcase/tstBitOperations.cpp	(revision 18569)
@@ -157,5 +157,5 @@
     struct TestMap *p = (struct TestMap *)RTTestGuardedAllocTail(hTest, sizeof(*p));
 #endif
-#define DUMP()          RTTestPrintf(hTest, "au32={%08x,%08x,%08x,%08x}", p->au32[0], p->au32[1], p->au32[2], p->au32[3])
+#define DUMP()          RTTestPrintf(hTest, RTTESTLVL_INFO, "au32={%08x,%08x,%08x,%08x}", p->au32[0], p->au32[1], p->au32[2], p->au32[3])
 #define CHECK(expr)     do { if (!(expr)) { RTTestFailed(hTest, "line %d: %s", __LINE__, #expr); DUMP(); } CHECK_GUARD(s); } while (0)
 #define CHECK_BIT(expr,  b1)            do { if (!(expr)) { RTTestFailed(hTest, "line %d, b1=%d: %s", __LINE__, b1, #expr); } CHECK_GUARD(s); } while (0)
