tstRTR0Common.h revision 7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4a
/* $Id$ */
/** @file
* IPRT R0 Testcase - Common header.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* 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.
*/
#ifndef ___testcase_tstRTR0Common_h
#define ___testcase_tstRTR0Common_h
#include <iprt/stdarg.h>
#include <iprt/string.h>
#include "tstRTR0CommonReq.h"
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Global error buffer used by macros and inline functions in this file. */
static char g_szErr[2048];
/**
* Service request handler prolog.
*
* Returns if the input is invalid. Initializes the return packet as well as
* the globals (g_szErr).
*
* @param pReqHdr The request packet header.
*/
#define RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr) \
do \
{ \
if (!VALID_PTR(pReqHdr)) \
return VERR_INVALID_PARAMETER; \
\
PRTTSTR0REQ pReq = (PRTTSTR0REQ)(pReqHdr); \
size_t cchErr = pReqHdr->cbReq - sizeof(pReq->Hdr); \
if (cchErr < 32 || cchErr >= 0x10000) \
return VERR_INVALID_PARAMETER; \
pReq->szMsg[0] = '\0'; \
\
/* Initialize the global buffer. */ \
memset(&g_szErr[0], 0, sizeof(g_szErr)); \
} while (0)
/**
* Service request handler epilog.
*
* Copies any errors or messages into the request packet.
*
* @param pReqHdr The request packet header.
*/
#define RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr) \
do \
{ \
PRTTSTR0REQ pReq = (PRTTSTR0REQ)(pReqHdr); \
size_t cbErr = pReqHdr->cbReq - sizeof(pReq->Hdr); \
if (g_szErr[0] && pReq->szMsg[0] != '!') \
RTStrCopyEx(pReq->szMsg, (cbErr), g_szErr, sizeof(g_szErr) - 1); \
} while (0)
/**
* Implement the sanity check switch-cases of a service request handler.
*/
#define RTR0TESTR0_IMPLEMENT_SANITY_CASES() \
case RTTSTR0REQ_SANITY_OK: \
break; \
case RTTSTR0REQ_SANITY_FAILURE: \
RTR0TestR0Error("42failure42%4096s", ""); \
break
/**
* Implements the default switch-case of a service request handler.
* @param uOperation The operation.
*/
#define RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation) \
default: \
RTR0TestR0Error("Unknown test #%d", (uOperation)); \
break
/**
* Macro for checking the return code of an API in the ring-0 testcase.
*
* Similar to RTTESTI_CHECK_RC.
*
* @param rcExpr The expression producing the return code. Only
* evaluated once.
* @param rcExpect The expected result. Evaluated multiple times.
*/
#define RTR0TESTR0_CHECK_RC(rcExpr, rcExpect) \
do { \
int rcCheck = (rcExpr); \
if (rcCheck != (rcExpect)) \
RTR0TestR0Error("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \
} while (0)
/**
* Same as RTR0TESTR0_CHECK_RC + break.
*/
#define RTR0TESTR0_CHECK_RC_BREAK(rcExpr, rcExpect) \
if (1) \
{ \
int rcCheck = (rcExpr); \
if (rcCheck != (rcExpect)) \
{ \
RTR0TestR0Error("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \
break; \
} \
} else do { } while (0)
/**
* Macro for checking the return code of an API in the ring-0 testcase.
*
* Similar to RTTESTI_CHECK_MSG
*
* @param expr The expression to evaluate.
* @param DetailsArgs Format string + arguments - in paranthesis.
*/
#define RTR0TESTR0_CHECK_MSG(expr, DetailsArgs) \
do { \
if (!(expr)) \
{ \
RTR0TestR0Error("line %u: expression failed: %s - ", __LINE__, #expr); \
RTR0TestR0AppendDetails DetailsArgs; \
} \
} while (0)
/**
* Same as RTR0TESTR0_CHECK_MSG + break.
*/
#define RTR0TESTR0_CHECK_MSG_BREAK(expr, DetailsArgs) \
if (!(expr)) \
{ \
RTR0TestR0Error("line %u: expression failed: %s - ", __LINE__, #expr); \
RTR0TestR0AppendDetails DetailsArgs; \
break; \
} else do { } while (0)
/**
* Same as RTR0TESTR0_CHECK_MSG + return @a rcRete.
*/
#define RTR0TESTR0_CHECK_MSG_RET(expr, DetailsArgs, rcRet) \
do { \
if (!(expr)) \
{ \
RTR0TestR0Error("line %u: expression failed: %s - ", __LINE__, #expr); \
RTR0TestR0AppendDetails DetailsArgs; \
return (rcRet); \
} \
} while (0)
/**
* Report an error.
*/
void RTR0TestR0Error(const char *pszFormat, ...)
{
size_t off = RTStrNLen(g_szErr, sizeof(g_szErr) - 1);
size_t cbLeft = sizeof(g_szErr) - off;
if (cbLeft > 10)
{
char *psz = &g_szErr[off];
if (off)
{
*psz++ = '\n';
*psz++ = '\n';
cbLeft -= 2;
}
*psz++ = '!';
cbLeft--;
va_list va;
va_start(va, pszFormat);
RTStrPrintfV(psz, cbLeft, pszFormat, va);
va_end(va);
}
}
/**
* Append error details.
*/
void RTR0TestR0AppendDetails(const char *pszFormat, ...)
{
size_t off = RTStrNLen(g_szErr, sizeof(g_szErr) - 1);
va_list va;
va_start(va, pszFormat);
RTStrPrintfV(&g_szErr[off], sizeof(g_szErr) - off, pszFormat, va);
va_end(va);
}
/**
* Informational message.
*/
void RTR0TestR0Info(const char *pszFormat, ...)
{
size_t off = RTStrNLen(g_szErr, sizeof(g_szErr) - 1);
size_t cbLeft = sizeof(g_szErr) - off;
if (cbLeft > 10)
{
char *psz = &g_szErr[off];
if (off)
{
*psz++ = '\n';
*psz++ = '\n';
cbLeft -= 2;
}
*psz++ = '?';
cbLeft--;
va_list va;
va_start(va, pszFormat);
RTStrPrintfV(psz, cbLeft, pszFormat, va);
va_end(va);
}
}
#endif