test.cpp revision 9c77b083e2ca3a9b509faa9789072f2527422e22
/* $Id$ */
/** @file
* IPRT - Testcase Framework.
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/critsect.h>
#include <iprt/initterm.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Guarded memory allocation record.
*/
typedef struct RTTESTGUARDEDMEM
{
/** Pointer to the next record. */
struct RTTESTGUARDEDMEM *pNext;
/** The address we return to the user. */
void *pvUser;
/** The base address of the allocation. */
void *pvAlloc;
/** The size of the allocation. */
/** Guards. */
struct
{
/** The guard address. */
void *pv;
/** The guard size. */
} aGuards[2];
/** Pointer to an guarded memory allocation. */
typedef RTTESTGUARDEDMEM *PRTTESTGUARDEDMEM;
/**
* Test instance structure.
*/
typedef struct RTTESTINT
{
/** Magic. */
/** The number of errors. */
/** The test name. */
const char *pszTest;
/** The length of the test name. */
/** The size of a guard. Multiple of PAGE_SIZE. */
/** The verbosity level. */
/** Critical section seralizing output. */
/** The output stream. */
/** Whether we're currently at a newline. */
bool fNewLine;
/** Critical section seralizing access to the members following it. */
/** The list of guarded memory allocations. */
/** The current sub-test. */
const char *pszSubTest;
/** The lenght of the sub-test name. */
/** Whether we've reported the sub-test result or not. */
bool fSubTestReported;
/** The start error count of the current subtest. */
/** The number of sub tests. */
/** The number of sub tests that failed. */
} RTTESTINT;
/** Pointer to a test instance. */
typedef RTTESTINT *PRTTESTINT;
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Validate a test instance. */
#define RTTEST_VALID_RETURN(pTest) \
do { \
} while (0)
/** Gets and validates a test instance.
* If the handle is nil, we will try retrive it from the test TLS entry.
*/
#define RTTEST_GET_VALID_RETURN(pTest) \
do { \
if (pTest == NIL_RTTEST) \
} while (0)
/** Gets and validates a test instance.
* If the handle is nil, we will try retrive it from the test TLS entry.
*/
do { \
if (pTest == NIL_RTTEST) \
} while (0)
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** For serializing TLS init. */
/** Our TLS entry. */
/**
* Init TLS index once.
*
* @returns IPRT status code.
* @param pvUser1 Ignored.
* @param pvUser2 Ignored.
*/
{
}
/**
* Creates a test instance.
*
* @returns IPRT status code.
* @param pszTest The test name.
* @param phTest Where to store the test instance handle.
*/
{
/*
* Global init.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Create the instance.
*/
if (!pTest)
return VERR_NO_MEMORY;
pTest->cchSubTest = 0;
pTest->fSubTestReported = true;
pTest->cSubTestAtErrors = 0;
pTest->cSubTestsFailed = 0;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/*
* Associate it with our TLS entry unless there is already
* an instance there.
*/
if (!RTTlsGet(g_iTestTls))
if (RT_SUCCESS(rc))
{
/*
* Finally, pick up overrides from the environment.
*/
char szMaxLevel[80];
if (RT_SUCCESS(rc))
{
}
return VINF_SUCCESS;
}
/* bail out. */
}
}
return rc;
}
{
if (RT_FAILURE(rc))
{
return RTEXITCODE_INIT;
}
if (RT_FAILURE(rc))
{
return RTEXITCODE_INIT;
}
return RTEXITCODE_SUCCESS;
}
/**
* Destroys a test instance previously created by RTTestCreate.
*
* @returns IPRT status code.
* @param hTest The test handle. NIL_RTTEST is ignored.
*/
{
/*
* Validate
*/
if (hTest == NIL_RTTEST)
return VINF_SUCCESS;
/*
* Make sure we end with a new line.
*/
/*
* Clean up.
*/
/* free guarded memory. */
while (pMem)
{
}
return VINF_SUCCESS;
}
/**
* Changes the default test instance for the calling thread.
*
* @returns IPRT status code.
*
* @param hNewDefaultTest The new default test. NIL_RTTEST is fine.
* @param phOldTest Where to store the old test handle. Optional.
*/
{
if (phOldTest)
}
/**
* Allocate a block of guarded memory.
*
* @returns IPRT status code.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param cb The amount of memory to allocate.
* @param cbAlign The alignment of the returned block.
* @param fHead Head or tail optimized guard.
* @param ppvUser Where to return the pointer to the block.
*/
RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser)
{
if (cbAlign == 0)
cbAlign = 1;
/*
* Allocate the record and block and initialize them.
*/
int rc = VERR_NO_MEMORY;
{
{
if (!fHead)
{
if (off)
{
}
}
/*
* Set up the guards and link the record.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
}
return rc;
}
/**
* Allocates a block of guarded memory where the guarded is immediately after
* the user memory.
*
* @returns Pointer to the allocated memory. NULL on failure.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param cb The amount of memory to allocate.
*/
{
void *pvUser;
if (RT_SUCCESS(rc))
return pvUser;
return NULL;
}
/**
* Allocates a block of guarded memory where the guarded is right in front of
* the user memory.
*
* @returns Pointer to the allocated memory. NULL on failure.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param cb The amount of memory to allocate.
*/
{
void *pvUser;
if (RT_SUCCESS(rc))
return pvUser;
return NULL;
}
/**
* Frees one block of guarded memory.
*
* The caller is responsible for unlinking it.
*
* @param pMem The memory record.
*/
{
int rc;
rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
}
/**
* Frees a block of guarded memory.
*
* @returns IPRT status code.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param pv The memory. NULL is ignored.
*/
{
if (!pv)
return VINF_SUCCESS;
/*
* Find it.
*/
int rc = VERR_INVALID_POINTER;
{
{
if (pPrev)
else
rc = VINF_SUCCESS;
break;
}
}
return VINF_SUCCESS;
}
/**
* Output callback.
*
* @returns number of bytes written.
* @param pvArg User argument.
* @param pachChars Pointer to an array of utf-8 characters.
* @param cbChars Number of bytes in the character array pointed to by pachChars.
*/
{
if (cbChars)
{
do
{
/* insert prefix if at a newline. */
{
}
/* look for newline and write the stuff. */
if (!pchEnd)
{
break;
}
} while (cbChars);
}
else
return cch;
}
/**
* Internal output worker.
*
* Caller takes the lock.
*
* @returns Number of chars printed.
* @param pTest The test instance.
* @param pszFormat The message.
* @param va The arguments.
*/
{
}
/**
* Internal output worker.
*
* Caller takes the lock.
*
* @returns Number of chars printed.
* @param pTest The test instance.
* @param pszFormat The message.
* @param ... The arguments.
*/
{
return cch;
}
/**
* Test vprintf making sure the output starts on a new line.
*
* @returns Number of chars printed.
* @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.
*/
{
int cch = 0;
{
}
return cch;
}
/**
* Test printf making sure the output starts on a new line.
*
* @returns Number of chars printed.
* @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.
*/
{
return cch;
}
/**
* Test vprintf, makes sure lines are prefixed and so forth.
*
* @returns Number of chars printed.
* @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.
*/
{
int cch = 0;
return cch;
}
/**
* Test printf, makes sure lines are prefixed and so forth.
*
* @returns Number of chars printed.
* @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.
*/
{
return cch;
}
/**
* Prints the test banner.
*
* @returns Number of chars printed.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
*/
{
}
/**
* 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.
*/
{
int cch = 0;
if ( !pTest->fSubTestReported
&& pTest->pszSubTest)
{
pTest->fSubTestReported = true;
if (!cErrors)
else
{
pTest->cSubTestsFailed++;
}
}
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.
*/
{
int cch = 0;
if (pTest->pszSubTest)
{
pTest->fSubTestReported = true;
}
return cch;
}
/**
* Summaries the test, destroys the test instance and return an exit code.
*
* @returns Test program exit code.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
*/
{
{
}
else
{
}
return enmExitCode;
}
{
{
if (pszReasonFmt)
}
else
{
}
return enmExitCode;
}
{
return enmExitCode;
}
/**
* 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
*/
{
/* Cleanup, reporting if necessary previous sub test. */
/* Start new sub test. */
pTest->fSubTestReported = false;
int cch = 0;
return cch;
}
/**
* Format string version of RTTestSub.
*
* See RTTestSub for details.
*
* @returns Number of chars printed.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param pszSubTestFmt The sub-test name format string.
* @param ... Arguments.
*/
{
return cch;
}
/**
* Format string version of RTTestSub.
*
* See RTTestSub for details.
*
* @returns Number of chars printed.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param pszSubTestFmt The sub-test name format string.
* @param ... Arguments.
*/
{
char *pszSubTest;
if (pszSubTest)
{
return cch;
}
return 0;
}
/**
* 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.
*/
{
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 va The arguments.
*/
{
int cch = 0;
{
}
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.
*/
{
return cch;
}
/**
* Increments the error counter.
*
* @returns IPRT status code.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
*/
{
return VINF_SUCCESS;
}
/**
* Get the current error count.
*
* @returns The error counter, UINT32_MAX if no valid test handle.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
*/
{
}
/**
* Increments the error counter and prints a failure message.
*
* @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.
*/
{
int cch = 0;
{
}
return cch;
}
/**
* Increments the error counter and prints a failure message.
*
* @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.
*/
{
return cch;
}
/**
* Same as RTTestPrintfV with RTTESTLVL_FAILURE.
*
* @returns Number of chars printed.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param pszFormat The message.
* @param va Arguments.
*/
{
}
/**
* Same as RTTestPrintf with RTTESTLVL_FAILURE.
*
* @returns Number of chars printed.
* @param hTest The test handle. If NIL_RTTEST we'll use the one
* associated with the calling thread.
* @param pszFormat The message.
* @param ... Arguments.
*/
{
return cch;
}