test.cpp revision 9c2453b230526193ea4d5cf5a735dbff69a85a36
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/* $Id$ */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/** @file
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * IPRT - Testcase Framework.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Copyright (C) 2009-2013 Oracle Corporation
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * available from http://www.virtualbox.org. This file is free software;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * General Public License (GPL) as published by the Free Software
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * The contents of this file may alternatively be used under the terms
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * of the Common Development and Distribution License Version 1.0
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * VirtualBox OSE distribution, in which case the provisions of the
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * CDDL are applicable instead of those of the GPL.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * You may elect to license modified versions of this file under the
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * terms and conditions of either the GPL or the CDDL or both.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/*******************************************************************************
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync* Header Files *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync*******************************************************************************/
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/test.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/asm.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/critsect.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/env.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/err.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/file.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/initterm.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/mem.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/once.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/param.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/pipe.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/string.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include <iprt/stream.h>
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#include "internal/magics.h"
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/*******************************************************************************
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync* Structures and Typedefs *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync*******************************************************************************/
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Guarded memory allocation record.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsynctypedef struct RTTESTGUARDEDMEM
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Pointer to the next record. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync struct RTTESTGUARDEDMEM *pNext;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The address we return to the user. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync void *pvUser;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The base address of the allocation. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync void *pvAlloc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The size of the allocation. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t cbAlloc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Guards. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync struct
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The guard address. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync void *pv;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The guard size. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t cb;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync } aGuards[2];
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync} RTTESTGUARDEDMEM;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/** Pointer to an guarded memory allocation. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsynctypedef RTTESTGUARDEDMEM *PRTTESTGUARDEDMEM;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Test instance structure.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsynctypedef struct RTTESTINT
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Magic. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync uint32_t u32Magic;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The number of errors. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync volatile uint32_t cErrors;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The test name. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync const char *pszTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The length of the test name. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t cchTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The size of a guard. Multiple of PAGE_SIZE. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync uint32_t cbGuard;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The verbosity level. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTESTLVL enmMaxLevel;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The creation flags. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync uint32_t fFlags;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Critical section serializing output. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCRITSECT OutputLock;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The output stream. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTSTREAM pOutStrm;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Whether we're currently at a newline. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync bool fNewLine;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Critical section serializing access to the members following it. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCRITSECT Lock;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The list of guarded memory allocations. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTGUARDEDMEM pGuardedMem;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The current sub-test. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync const char *pszSubTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The length of the sub-test name. */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync size_t cchSubTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Whether the current subtest should figure as 'SKIPPED'. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync bool fSubTestSkipped;
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync /** Whether we've reported the sub-test result or not. */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync bool fSubTestReported;
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync /** The start error count of the current subtest. */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync uint32_t cSubTestAtErrors;
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync /** The number of sub tests. */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync uint32_t cSubTests;
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync /** The number of sub tests that failed. */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync uint32_t cSubTestsFailed;
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Set if XML output is enabled. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync bool fXmlEnabled;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Set if we omit the top level test in the XML report. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync bool fXmlOmitTopTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Set if we've reported the top test (for RTTEST_C_XML_DELAY_TOP_TEST). */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync bool fXmlTopTestDone;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync enum {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync kXmlPos_ValueStart,
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync kXmlPos_Value,
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync kXmlPos_ElementEnd
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync } eXmlState;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** Test pipe for the XML output stream going to the server. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTPIPE hXmlPipe;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** File where the XML output stream might be directed. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTFILE hXmlFile;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** The number of XML elements on the stack. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t cXmlElements;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /** XML element stack. */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync const char *apszXmlElements[10];
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync} RTTESTINT;
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync/** Pointer to a test instance. */
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsynctypedef RTTESTINT *PRTTESTINT;
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync/*******************************************************************************
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync* Defined Constants And Macros *
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync*******************************************************************************/
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync/** Validate a test instance. */
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync#define RTTEST_VALID_RETURN(pTest) \
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync do { \
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync AssertPtrReturn(pTest, VERR_INVALID_HANDLE); \
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, VERR_INVALID_HANDLE); \
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync } while (0)
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync/** Gets and validates a test instance.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * If the handle is nil, we will try retrieve it from the test TLS entry.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync */
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync#define RTTEST_GET_VALID_RETURN(pTest) \
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync do { \
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync if (pTest == NIL_RTTEST) \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest = (PRTTESTINT)RTTlsGet(g_iTestTls); \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertPtrReturn(pTest, VERR_INVALID_HANDLE); \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, VERR_INVALID_MAGIC); \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync } while (0)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/** Gets and validates a test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * If the handle is nil, we will try retrieve it from the test TLS entry.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#define RTTEST_GET_VALID_RETURN_RC(pTest, rc) \
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync do { \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest == NIL_RTTEST) \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest = (PRTTESTINT)RTTlsGet(g_iTestTls); \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertPtrReturn(pTest, (rc)); \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturn(pTest->u32Magic == RTTESTINT_MAGIC, (rc)); \
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync } while (0)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/*******************************************************************************
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync* Internal Functions *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync*******************************************************************************/
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlEnd(PRTTESTINT pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/*******************************************************************************
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync* Global Variables *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync*******************************************************************************/
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/** For serializing TLS init. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic RTONCE g_TestInitOnce = RTONCE_INITIALIZER;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/** Our TLS entry. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic RTTLS g_iTestTls = NIL_RTTLS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Init TLS index once.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns IPRT status code.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pvUser Ignored.
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsyncstatic DECLCALLBACK(int32_t) rtTestInitOnce(void *pvUser)
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync{
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync NOREF(pvUser);
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync return RTTlsAllocEx(&g_iTestTls, NULL);
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync}
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsyncRTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel,
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest)
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync{
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync AssertReturn(!(fFlags & ~RTTEST_C_VALID_MASK), VERR_INVALID_PARAMETER);
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync AssertPtrNull(phTest);
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync AssertPtrNull(pszXmlFile);
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync /* RTTESTLVL_INVALID is valid! */
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync AssertReturn(enmMaxLevel >= RTTESTLVL_INVALID && enmMaxLevel < RTTESTLVL_END, VERR_INVALID_PARAMETER);
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync /*
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync * Global init.
b011d23442f2b9e7208db889ff4b5ffe2c8effc8vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc = RTOnce(&g_TestInitOnce, rtTestInitOnce, NULL);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_FAILURE(rc))
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync return rc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Create the instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTINT pTest = (PRTTESTINT)RTMemAllocZ(sizeof(*pTest));
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!pTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VERR_NO_MEMORY;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->u32Magic = RTTESTINT_MAGIC;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pszTest = RTStrDup(pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cchTest = strlen(pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cbGuard = PAGE_SIZE * 7;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = enmMaxLevel == RTTESTLVL_INVALID ? RTTESTLVL_INFO : enmMaxLevel;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fFlags = fFlags;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync pTest->pOutStrm = g_pStdOut;
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync pTest->fNewLine = true;
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync pTest->pGuardedMem = NULL;
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync pTest->pszSubTest = NULL;
bd720a6cefa808ffed334825a272cc0d3f2680b8vboxsync pTest->cchSubTest = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fSubTestSkipped = false;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fSubTestReported = true;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cSubTestAtErrors = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cSubTests = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cSubTestsFailed = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fXmlEnabled = false;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fXmlTopTestDone = false;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->hXmlPipe = NIL_RTPIPE;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->hXmlFile = NIL_RTFILE;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cXmlElements = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTCritSectInit(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTCritSectInit(&pTest->OutputLock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Associate it with our TLS entry unless there is already
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * an instance there.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if ( !(fFlags & RTTEST_C_NO_TLS)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync && !RTTlsGet(g_iTestTls))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTTlsSet(g_iTestTls, pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Output level override?
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char szEnvVal[RTPATH_MAX];
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if ((fFlags & RTTEST_C_USE_ENV) && enmMaxLevel == RTTESTLVL_INVALID)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_MAX_LEVEL", szEnvVal, sizeof(szEnvVal), NULL);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char *pszMaxLevel = RTStrStrip(szEnvVal);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!strcmp(pszMaxLevel, "all"))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = RTTESTLVL_DEBUG;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!strcmp(pszMaxLevel, "quiet"))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = RTTESTLVL_FAILURE;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (!strcmp(pszMaxLevel, "debug"))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = RTTESTLVL_DEBUG;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (!strcmp(pszMaxLevel, "info"))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = RTTESTLVL_INFO;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (!strcmp(pszMaxLevel, "sub_test"))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = RTTESTLVL_SUB_TEST;
f4859dbc9e6e61d81adba530beddf0c374ac9011vboxsync else if (!strcmp(pszMaxLevel, "failure"))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->enmMaxLevel = RTTESTLVL_FAILURE;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (rc != VERR_ENV_VAR_NOT_FOUND)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Any test driver we are connected or should connect to?
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if ((fFlags & RTTEST_C_USE_ENV) && iNativeTestPipe == -1)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_PIPE", szEnvVal, sizeof(szEnvVal), NULL);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#if ARCH_BITS == 64
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTStrToInt64Full(szEnvVal, 0, &iNativeTestPipe);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTStrToInt32Full(szEnvVal, 0, &iNativeTestPipe);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync#endif
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_FAILURE(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTStrToInt32Full(\"%s\") -> %Rrc\n",
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pszTest, szEnvVal, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync iNativeTestPipe = -1;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (rc != VERR_ENV_VAR_NOT_FOUND)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_PIPE) -> %Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (iNativeTestPipe != -1)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTPipeFromNative(&pTest->hXmlPipe, iNativeTestPipe, RTPIPE_N_WRITE);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fXmlEnabled = true;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
2805b95732a8d26015a397626b96049a6e6573e7vboxsync RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTPipeFromNative(,%p,WRITE) -> %Rrc\n",
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pszTest, iNativeTestPipe, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->hXmlPipe = NIL_RTPIPE;
7f17f0ea0209f234bdebdf0509c0e2b74e732f69vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Any test file we should write the test report to?
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if ((fFlags & RTTEST_C_USE_ENV) && pszXmlFile == NULL)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTEnvGetEx(RTENV_DEFAULT, "IPRT_TEST_FILE", szEnvVal, sizeof(szEnvVal), NULL);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pszXmlFile = szEnvVal;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (rc != VERR_ENV_VAR_NOT_FOUND)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: test pipe error: RTEnvGetEx(IPRT_TEST_MAX_LEVEL) -> %Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pszXmlFile && *pszXmlFile)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTFileOpen(&pTest->hXmlFile, pszXmlFile,
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fXmlEnabled = true;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: test file error: RTFileOpen(,\"%s\",) -> %Rrc\n", pszTest, pszXmlFile, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->hXmlFile = NIL_RTFILE;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (rc != VERR_ENV_VAR_NOT_FOUND)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: test file error: RTEnvGetEx(IPRT_TEST_FILE) -> %Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * What do we report in the XML stream/file.?
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->fXmlOmitTopTest = (fFlags & RTTEST_C_XML_OMIT_TOP_TEST)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync || ( (fFlags & RTTEST_C_USE_ENV)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync && RTEnvExistEx(RTENV_DEFAULT, "IPRT_TEST_OMIT_TOP_TEST"));
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Tell the test driver that we're up to.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlStart(pTest, pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *phTest = pTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /* bail out. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectDelete(&pTest->OutputLock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectDelete(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->u32Magic = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrFree((char *)pTest->pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemFree(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return rc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return RTTestCreateEx(pszTest, RTTEST_C_USE_ENV, RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, NULL /*pszXmlFile*/, phTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc = RTR3InitExeNoArguments(0);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_FAILURE(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExeNoArguments failed with rc=%Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return RTEXITCODE_INIT;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTTestCreate(pszTest, phTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_FAILURE(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return RTEXITCODE_INIT;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return RTEXITCODE_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***papszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (cArgs <= 0 && papszArgs == NULL)
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync rc = RTR3InitExeNoArguments(fRtInit);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTR3InitExe(cArgs, papszArgs, fRtInit);
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync if (RT_FAILURE(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrmPrintf(g_pStdErr, "%s: fatal error: RTR3InitExe(,,%#x) failed with rc=%Rrc\n", pszTest, fRtInit, rc);
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync return RTEXITCODE_INIT;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTTestCreate(pszTest, phTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_FAILURE(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync RTStrmPrintf(g_pStdErr, "%s: fatal error: RTTestCreate failed with rc=%Rrc\n", pszTest, rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return RTEXITCODE_INIT;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync return RTEXITCODE_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Destroys a test instance previously created by RTTestCreate.
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns IPRT status code.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param hTest The test handle. NIL_RTTEST is ignored.
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(int) RTTestDestroy(RTTEST hTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Validate
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (hTest == NIL_RTTEST)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTESTINT *pTest = hTest;
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync RTTEST_VALID_RETURN(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * Make sure we end with a new line and have finished up the XML.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!pTest->fNewLine)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestPrintf(pTest, "\n");
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlEnd(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Clean up.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if ((RTTESTINT *)RTTlsGet(g_iTestTls) == pTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTlsSet(g_iTestTls, NULL);
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync ASMAtomicWriteU32(&pTest->u32Magic, ~RTTESTINT_MAGIC);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectDelete(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectDelete(&pTest->OutputLock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /* free guarded memory. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pGuardedMem = NULL;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync while (pMem)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTGUARDEDMEM pFree = pMem;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem = pMem->pNext;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestGuardedFreeOne(pFree);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrFree((char *)pTest->pszSubTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pszSubTest = NULL;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrFree((char *)pTest->pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pszTest = NULL;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemFree(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Changes the default test instance for the calling thread.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns IPRT status code.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param hNewDefaultTest The new default test. NIL_RTTEST is fine.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param phOldTest Where to store the old test handle. Optional.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (phOldTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *phOldTest = (RTTEST)RTTlsGet(g_iTestTls);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return RTTlsSet(g_iTestTls, hNewDefaultTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTINT pTest = hTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTEST_GET_VALID_RETURN(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertPtrReturn(pszName, VERR_INVALID_POINTER);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturn(*pszName, VERR_INVALID_PARAMETER);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t cchName = strlen(pszName);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturn(cchName < 128, VERR_INVALID_PARAMETER);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char *pszDupName = RTStrDup(pszName);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!pszDupName)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VERR_NO_STR_MEMORY;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
f4859dbc9e6e61d81adba530beddf0c374ac9011vboxsync RTCritSectEnter(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectEnter(&pTest->OutputLock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char *pszOldName = (char *)pTest->pszTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pszTest = pszDupName;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cchTest = cchName;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectLeave(&pTest->OutputLock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectLeave(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrFree(pszOldName);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * Allocate a block of guarded memory.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns IPRT status code.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param hTest The test handle. If NIL_RTTEST we'll use the one
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * associated with the calling thread.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param cb The amount of memory to allocate.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param cbAlign The alignment of the returned block.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param fHead Head or tail optimized guard.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param ppvUser Where to return the pointer to the block.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTINT pTest = hTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTEST_GET_VALID_RETURN(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (cbAlign == 0)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync cbAlign = 1;
2805b95732a8d26015a397626b96049a6e6573e7vboxsync AssertReturn(cbAlign <= PAGE_SIZE, VERR_INVALID_PARAMETER);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturn(cbAlign == (UINT32_C(1) << (ASMBitFirstSetU32(cbAlign) - 1)), VERR_INVALID_PARAMETER);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Allocate the record and block and initialize them.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc = VERR_NO_MEMORY;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTGUARDEDMEM pMem = (PRTTESTGUARDEDMEM)RTMemAlloc(sizeof(*pMem));
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_LIKELY(pMem))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t const cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
f4859dbc9e6e61d81adba530beddf0c374ac9011vboxsync pMem->aGuards[0].cb = pMem->aGuards[1].cb = pTest->cbGuard;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->cbAlloc = pMem->aGuards[0].cb + pMem->aGuards[1].cb + cbAligned;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->pvAlloc = RTMemPageAlloc(pMem->cbAlloc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pMem->pvAlloc)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->aGuards[0].pv = pMem->pvAlloc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->pvUser = (uint8_t *)pMem->pvAlloc + pMem->aGuards[0].cb;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->aGuards[1].pv = (uint8_t *)pMem->pvUser + cbAligned;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!fHead)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t off = cb & PAGE_OFFSET_MASK;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (off)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync off = PAGE_SIZE - RT_ALIGN_Z(off, cbAlign);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->pvUser = (uint8_t *)pMem->pvUser + off;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Set up the guards and link the record.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync ASMMemFill32(pMem->aGuards[0].pv, pMem->aGuards[0].cb, 0xdeadbeef);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync ASMMemFill32(pMem->aGuards[1].pv, pMem->aGuards[1].cb, 0xdeadbeef);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_NONE);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_NONE);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *ppvUser = pMem->pvUser;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectEnter(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pMem->pNext = pTest->pGuardedMem;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pGuardedMem = pMem;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectLeave(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemPageFree(pMem->pvAlloc, pMem->cbAlloc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemFree(pMem);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return rc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Allocates a block of guarded memory where the guarded is immediately after
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * the user memory.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns Pointer to the allocated memory. NULL on failure.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param hTest The test handle. If NIL_RTTEST we'll use the one
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * associated with the calling thread.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param cb The amount of memory to allocate.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync void *pvUser;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc = RTTestGuardedAlloc(hTest, cb, 1, false /*fHead*/, &pvUser);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return pvUser;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return NULL;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Allocates a block of guarded memory where the guarded is right in front of
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * the user memory.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns Pointer to the allocated memory. NULL on failure.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param hTest The test handle. If NIL_RTTEST we'll use the one
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * associated with the calling thread.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param cb The amount of memory to allocate.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync void *pvUser;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc = RTTestGuardedAlloc(hTest, cb, 1, true /*fHead*/, &pvUser);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (RT_SUCCESS(rc))
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return pvUser;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return NULL;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
2805b95732a8d26015a397626b96049a6e6573e7vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Frees one block of guarded memory.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * The caller is responsible for unlinking it.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pMem The memory record.
7f17f0ea0209f234bdebdf0509c0e2b74e732f69vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestGuardedFreeOne(PRTTESTGUARDEDMEM pMem)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTMemProtect(pMem->aGuards[0].pv, pMem->aGuards[0].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = RTMemProtect(pMem->aGuards[1].pv, pMem->aGuards[1].cb, RTMEM_PROT_WRITE | RTMEM_PROT_READ); AssertRC(rc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemPageFree(pMem->pvAlloc, pMem->cbAlloc);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTMemFree(pMem);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Frees a block of guarded memory.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @returns IPRT status code.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param hTest The test handle. If NIL_RTTEST we'll use the one
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * associated with the calling thread.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pv The memory. NULL is ignored.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncRTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTINT pTest = hTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTEST_GET_VALID_RETURN(pTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!pv)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /*
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Find it.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync int rc = VERR_INVALID_POINTER;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync PRTTESTGUARDEDMEM pPrev = NULL;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectEnter(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync for (PRTTESTGUARDEDMEM pMem = pTest->pGuardedMem; pMem; pMem = pMem->pNext)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pMem->pvUser == pv)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pPrev)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pPrev->pNext = pMem->pNext;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->pGuardedMem = pMem->pNext;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestGuardedFreeOne(pMem);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rc = VINF_SUCCESS;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync break;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pPrev = pMem;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTCritSectLeave(&pTest->Lock);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync return rc;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * Outputs the formatted XML.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pTest The test instance.
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * @param pszFormat The format string.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param va The format arguments.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsyncstatic void rtTestXmlOutputV(PRTTESTINT pTest, const char *pszFormat, va_list va)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlEnabled)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char *pszStr;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync ssize_t cchStr = RTStrAPrintfV(&pszStr, pszFormat, va);
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync if (pszStr)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->hXmlPipe != NIL_RTPIPE)
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync RTPipeWriteBlocking(pTest->hXmlPipe, pszStr, cchStr, NULL);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->hXmlFile != NIL_RTFILE)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTFileWrite(pTest->hXmlFile, pszStr, cchStr, NULL);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTStrFree(pszStr);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Outputs the formatted XML.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * @param pTest The test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszFormat The format string.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param ... The format arguments.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlOutput(PRTTESTINT pTest, const char *pszFormat, ...)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync va_list va;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_start(va, pszFormat);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutputV(pTest, pszFormat, va);
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync va_end(va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * Starts the XML stream.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pTest The test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszTest The test name.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlStart(PRTTESTINT pTest, const char *pszTest)
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cXmlElements = 0;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlEnabled)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
f4859dbc9e6e61d81adba530beddf0c374ac9011vboxsync pTest->fXmlTopTestDone = !(pTest->fFlags & RTTEST_C_XML_DELAY_TOP_TEST) || pTest->fXmlOmitTopTest;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlTopTestDone && !pTest->fXmlOmitTopTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszTest);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Emit an XML element that doesn't have any value and instead ends immediately.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * The caller must own the instance lock.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pTest The test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszTag The element tag.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszAttrFmt The element attributes as a format string. Use
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * NULL if none.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param va Format string arguments.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlEnabled)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTIMESPEC TimeSpec;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTIME Time;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char szTS[80];
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "\n");
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!pszAttrFmt || !*pszAttrFmt)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas/>\n",
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cXmlElements * 2, "", pszTag, szTS);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_list va2;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_copy(va2, va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N/>\n",
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cXmlElements * 2, "", pszTag, szTS, pszAttrFmt, &va2);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_end(va2);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Wrapper around rtTestXmlElemV.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElem(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_list va;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_start(va, pszAttrFmt);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlElemV(pTest, pszTag, pszAttrFmt, va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_end(va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Starts a new XML element.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * The caller must own the instance lock.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pTest The test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszTag The element tag.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszAttrFmt The element attributes as a format string. Use
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * NULL if none.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param va Format string arguments.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemStartV(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, va_list va)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /* Push it onto the stack. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync size_t i = pTest->cXmlElements;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturnVoid(i < RT_ELEMENTS(pTest->apszXmlElements));
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->apszXmlElements[i] = pszTag;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cXmlElements = i + 1;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlEnabled)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTIMESPEC TimeSpec;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTIME Time;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync char szTS[80];
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&TimeSpec)), szTS, sizeof(szTS));
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->eXmlState != RTTESTINT::kXmlPos_ElementEnd)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "\n");
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (!pszAttrFmt || !*pszAttrFmt)
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas>",
f2d4fe7c062d5d0501fadae94d1d3521bf31e4acvboxsync i * 2, "", pszTag, szTS);
f2d4fe7c062d5d0501fadae94d1d3521bf31e4acvboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_list va2;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_copy(va2, va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "%*s<%s timestamp=%RMas %N>",
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync i * 2, "", pszTag, szTS, pszAttrFmt, &va2);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_end(va2);
f4859dbc9e6e61d81adba530beddf0c374ac9011vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->eXmlState = RTTESTINT::kXmlPos_ValueStart;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Wrapper around rtTestXmlElemStartV.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemStart(PRTTESTINT pTest, const char *pszTag, const char *pszAttrFmt, ...)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync va_list va;
f2d4fe7c062d5d0501fadae94d1d3521bf31e4acvboxsync va_start(va, pszAttrFmt);
f2d4fe7c062d5d0501fadae94d1d3521bf31e4acvboxsync rtTestXmlElemStartV(pTest, pszTag, pszAttrFmt, va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync va_end(va);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Ends the current element.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * The caller must own the instance lock.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync * @param pTest The test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pszTag The tag we're ending (chiefly for sanity
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * checking).
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlElemEnd(PRTTESTINT pTest, const char *pszTag)
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync{
f2d4fe7c062d5d0501fadae94d1d3521bf31e4acvboxsync /* pop the element */
f2d4fe7c062d5d0501fadae94d1d3521bf31e4acvboxsync size_t i = pTest->cXmlElements;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturnVoid(i > 0);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync i--;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync AssertReturnVoid(!strcmp(pszTag, pTest->apszXmlElements[i]));
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync pTest->cXmlElements = i;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync /* Do the closing. */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlEnabled)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync else
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync rtTestXmlOutput(pTest, "</%s>\n", pszTag);
df3faec6dead5801ee07120bff7940a2c8ed6296vboxsync pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync }
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync}
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync/**
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * Ends the XML stream, closing all open elements.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * The caller must own the instance lock.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync *
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync * @param pTest The test instance.
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync */
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsyncstatic void rtTestXmlEnd(PRTTESTINT pTest)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync{
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync if (pTest->fXmlEnabled)
e1fd337d575f2a4c053c6fe7a811e2fd1a31e874vboxsync {
/*
* Close all the elements and add the final TestEnd one to get a
* final timestamp and some certainty that the XML is valid.
*/
size_t i = pTest->cXmlElements;
AssertReturnVoid(i > 0 || pTest->fXmlOmitTopTest || !pTest->fXmlTopTestDone);
while (i-- > 1)
{
const char *pszTag = pTest->apszXmlElements[pTest->cXmlElements];
if (pTest->eXmlState == RTTESTINT::kXmlPos_ValueStart)
rtTestXmlOutput(pTest, "\n%*s</%s>\n", i * 2, "", pszTag);
else if (pTest->eXmlState == RTTESTINT::kXmlPos_ElementEnd)
rtTestXmlOutput(pTest, "%*s</%s>\n", i * 2, "", pszTag);
else
rtTestXmlOutput(pTest, "</%s>\n", pszTag);
pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
}
if (!pTest->fXmlOmitTopTest && pTest->fXmlTopTestDone)
{
rtTestXmlElem(pTest, "End", "SubTests=\"%u\" SubTestsFailed=\"%u\" errors=\"%u\"",
pTest->cSubTests, pTest->cSubTestsFailed, pTest->cErrors);
rtTestXmlOutput(pTest, "</Test>\n");
}
/*
* Close the XML outputs.
*/
if (pTest->hXmlPipe != NIL_RTPIPE)
{
RTPipeClose(pTest->hXmlPipe);
pTest->hXmlPipe = NIL_RTPIPE;
}
if (pTest->hXmlFile != NIL_RTFILE)
{
RTFileClose(pTest->hXmlFile);
pTest->hXmlFile = NIL_RTFILE;
}
pTest->fXmlEnabled = false;
pTest->eXmlState = RTTESTINT::kXmlPos_ElementEnd;
}
pTest->cXmlElements = 0;
}
/**
* 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.
*/
static DECLCALLBACK(size_t) rtTestPrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
{
size_t cch = 0;
PRTTESTINT pTest = (PRTTESTINT)pvArg;
if (cbChars)
{
do
{
/* insert prefix if at a newline. */
if (pTest->fNewLine)
{
RTStrmWrite(pTest->pOutStrm, pTest->pszTest, pTest->cchTest);
RTStrmWrite(pTest->pOutStrm, ": ", 2);
cch += 2 + pTest->cchTest;
}
/* look for newline and write the stuff. */
const char *pchEnd = (const char *)memchr(pachChars, '\n', cbChars);
if (!pchEnd)
{
pTest->fNewLine = false;
RTStrmWrite(pTest->pOutStrm, pachChars, cbChars);
cch += cbChars;
break;
}
pTest->fNewLine = true;
size_t const cchPart = pchEnd - pachChars + 1;
RTStrmWrite(pTest->pOutStrm, pachChars, cchPart);
cch += cchPart;
pachChars += cchPart;
cbChars -= cchPart;
} while (cbChars);
}
else
RTStrmFlush(pTest->pOutStrm);
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.
*/
static int rtTestPrintfV(PRTTESTINT pTest, const char *pszFormat, va_list va)
{
return (int)RTStrFormatV(rtTestPrintfOutput, pTest, NULL, NULL, pszFormat, va);
}
/**
* Internal output worker.
*
* Caller takes the lock.
*
* @returns Number of chars printed.
* @param pTest The test instance.
* @param pszFormat The message.
* @param ... The arguments.
*/
static int rtTestPrintf(PRTTESTINT pTest, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int cch = rtTestPrintfV(pTest, pszFormat, va);
va_end(va);
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.
*/
RTR3DECL(int) RTTestPrintfNlV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, -1);
RTCritSectEnter(&pTest->OutputLock);
int cch = 0;
if (enmLevel <= pTest->enmMaxLevel)
{
if (!pTest->fNewLine)
cch += rtTestPrintf(pTest, "\n");
cch += rtTestPrintfV(pTest, pszFormat, va);
}
RTCritSectLeave(&pTest->OutputLock);
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.
*/
RTR3DECL(int) RTTestPrintfNl(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int cch = RTTestPrintfNlV(hTest, enmLevel, pszFormat, va);
va_end(va);
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.
*/
RTR3DECL(int) RTTestPrintfV(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, -1);
RTCritSectEnter(&pTest->OutputLock);
int cch = 0;
if (enmLevel <= pTest->enmMaxLevel)
cch += rtTestPrintfV(pTest, pszFormat, va);
RTCritSectLeave(&pTest->OutputLock);
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.
*/
RTR3DECL(int) RTTestPrintf(RTTEST hTest, RTTESTLVL enmLevel, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int cch = RTTestPrintfV(hTest, enmLevel, pszFormat, va);
va_end(va);
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.
*/
RTR3DECL(int) RTTestBanner(RTTEST hTest)
{
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)
{
if (!pTest->fSubTestSkipped)
{
rtTestXmlElem(pTest, "Passed", NULL);
rtTestXmlElemEnd(pTest, "Test");
cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: PASSED\n", pTest->pszSubTest);
}
else
{
rtTestXmlElem(pTest, "Skipped", NULL);
rtTestXmlElemEnd(pTest, "Test");
cch += RTTestPrintfNl(pTest, RTTESTLVL_SUB_TEST, "%-50s: SKIPPED\n", pTest->pszSubTest);
}
}
else
{
pTest->cSubTestsFailed++;
rtTestXmlElem(pTest, "Failed", "errors=\"%u\"", cErrors);
rtTestXmlElemEnd(pTest, "Test");
cch += RTTestPrintfNl(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;
}
/**
* 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.
*/
RTR3DECL(RTEXITCODE) RTTestSummaryAndDestroy(RTTEST hTest)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_FAILURE);
RTCritSectEnter(&pTest->Lock);
rtTestSubTestReport(pTest);
RTCritSectLeave(&pTest->Lock);
RTEXITCODE enmExitCode;
if (!pTest->cErrors)
{
RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SUCCESS\n", pTest->cErrors);
enmExitCode = RTEXITCODE_SUCCESS;
}
else
{
RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
enmExitCode = RTEXITCODE_FAILURE;
}
RTTestDestroy(pTest);
return enmExitCode;
}
RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, RTEXITCODE_SKIPPED);
RTCritSectEnter(&pTest->Lock);
rtTestSubTestReport(pTest);
RTCritSectLeave(&pTest->Lock);
RTEXITCODE enmExitCode;
if (!pTest->cErrors)
{
if (pszReasonFmt)
RTTestPrintfNlV(hTest, RTTESTLVL_FAILURE, pszReasonFmt, va);
RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "SKIPPED\n", pTest->cErrors);
enmExitCode = RTEXITCODE_SKIPPED;
}
else
{
RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "FAILURE - %u errors\n", pTest->cErrors);
enmExitCode = RTEXITCODE_FAILURE;
}
RTTestDestroy(pTest);
return enmExitCode;
}
RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...)
{
va_list va;
va_start(va, pszReasonFmt);
RTEXITCODE enmExitCode = RTTestSkipAndDestroyV(hTest, pszReasonFmt, va);
va_end(va);
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
*/
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->fSubTestSkipped = false;
pTest->fSubTestReported = false;
int cch = 0;
if (pTest->enmMaxLevel >= RTTESTLVL_DEBUG)
cch = RTTestPrintfNl(hTest, RTTESTLVL_DEBUG, "debug: Starting sub-test '%s'\n", pszSubTest);
if (!pTest->fXmlTopTestDone)
{
pTest->fXmlTopTestDone = true;
rtTestXmlElemStart(pTest, "Test", "name=%RMas", pTest->pszTest);
}
rtTestXmlElemStart(pTest, "Test", "name=%RMas", pszSubTest);
RTCritSectLeave(&pTest->Lock);
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.
*/
RTR3DECL(int) RTTestSubF(RTTEST hTest, const char *pszSubTestFmt, ...)
{
va_list va;
va_start(va, pszSubTestFmt);
int cch = RTTestSubV(hTest, pszSubTestFmt, va);
va_end(va);
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.
*/
RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va)
{
char *pszSubTest;
RTStrAPrintfV(&pszSubTest, pszSubTestFmt, va);
if (pszSubTest)
{
int cch = RTTestSub(hTest, pszSubTest);
RTStrFree(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.
*/
RTR3DECL(int) RTTestSubDone(RTTEST hTest)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
RTCritSectEnter(&pTest->Lock);
int cch = rtTestSubCleanup(pTest);
RTCritSectLeave(&pTest->Lock);
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.
*/
RTR3DECL(int) RTTestPassedV(RTTEST hTest, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
AssertPtr(pszFormat);
RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
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;
}
RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
AssertPtrNull(pszFormat);
RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
pTest->fSubTestSkipped = true;
int cch = 0;
if (pszFormat && *pszFormat && 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;
}
RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int cch = RTTestSkippedV(hTest, pszFormat, va);
va_end(va);
return cch;
}
/**
* Gets the unit name.
*
* @returns Unit name.
* @param enmUnit The unit.
*/
static const char *rtTestUnitName(RTTESTUNIT enmUnit)
{
switch (enmUnit)
{
case RTTESTUNIT_PCT: return "%";
case RTTESTUNIT_BYTES: return "bytes";
case RTTESTUNIT_BYTES_PER_SEC: return "bytes/s";
case RTTESTUNIT_KILOBYTES: return "KB";
case RTTESTUNIT_KILOBYTES_PER_SEC: return "KB/s";
case RTTESTUNIT_MEGABYTES: return "MB";
case RTTESTUNIT_MEGABYTES_PER_SEC: return "MB/s";
case RTTESTUNIT_PACKETS: return "packets";
case RTTESTUNIT_PACKETS_PER_SEC: return "packets/s";
case RTTESTUNIT_FRAMES: return "frames";
case RTTESTUNIT_FRAMES_PER_SEC: return "frames/";
case RTTESTUNIT_OCCURRENCES: return "occurrences";
case RTTESTUNIT_OCCURRENCES_PER_SEC: return "occurrences/s";
case RTTESTUNIT_ROUND_TRIP: return "roundtrips";
case RTTESTUNIT_CALLS: return "calls";
case RTTESTUNIT_CALLS_PER_SEC: return "calls/s";
case RTTESTUNIT_SECS: return "s";
case RTTESTUNIT_MS: return "ms";
case RTTESTUNIT_NS: return "ns";
case RTTESTUNIT_NS_PER_CALL: return "ns/call";
case RTTESTUNIT_NS_PER_FRAME: return "ns/frame";
case RTTESTUNIT_NS_PER_OCCURRENCE: return "ns/occurrences";
case RTTESTUNIT_NS_PER_PACKET: return "ns/packet";
case RTTESTUNIT_NS_PER_ROUND_TRIP: return "ns/roundtrips";
case RTTESTUNIT_INSTRS: return "ins";
case RTTESTUNIT_INSTRS_PER_SEC: return "ins/sec";
case RTTESTUNIT_NONE: return "";
case RTTESTUNIT_PP1K: return "pp1k";
case RTTESTUNIT_PP10K: return "pp10k";
case RTTESTUNIT_PPM: return "ppm";
case RTTESTUNIT_PPB: return "ppb";
/* No default so gcc helps us keep this up to date. */
case RTTESTUNIT_INVALID:
case RTTESTUNIT_END:
break;
}
AssertMsgFailed(("%d\n", enmUnit));
return "unknown";
}
RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN(pTest);
const char *pszUnit = rtTestUnitName(enmUnit);
RTCritSectEnter(&pTest->Lock);
rtTestXmlElem(pTest, "Value", "name=%RMas unit=%RMas value=\"%llu\"", pszName, pszUnit, u64Value);
RTCritSectLeave(&pTest->Lock);
RTCritSectEnter(&pTest->OutputLock);
rtTestPrintf(pTest, " %-48s: %'16llu %s\n", pszName, u64Value, pszUnit);
RTCritSectLeave(&pTest->OutputLock);
return VINF_SUCCESS;
}
RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...)
{
va_list va;
va_start(va, pszNameFmt);
int rc = RTTestValueV(hTest, u64Value, enmUnit, pszNameFmt, va);
va_end(va);
return rc;
}
RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va)
{
char *pszName;
RTStrAPrintfV(&pszName, pszNameFmt, va);
if (!pszName)
return VERR_NO_MEMORY;
int rc = RTTestValue(hTest, pszName, u64Value, enmUnit);
RTStrFree(pszName);
return rc;
}
/**
* 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.
*/
RTR3DECL(int) RTTestErrorInc(RTTEST hTest)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN(pTest);
ASMAtomicIncU32(&pTest->cErrors);
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.
*/
RTR3DECL(uint32_t) RTTestErrorCount(RTTEST hTest)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
return ASMAtomicReadU32(&pTest->cErrors);
}
RTR3DECL(uint32_t) RTTestSubErrorCount(RTTEST hTest)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, UINT32_MAX);
return ASMAtomicReadU32(&pTest->cErrors) - pTest->cSubTestAtErrors;
}
/**
* 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.
*/
RTR3DECL(int) RTTestFailedV(RTTEST hTest, const char *pszFormat, va_list va)
{
PRTTESTINT pTest = hTest;
RTTEST_GET_VALID_RETURN_RC(pTest, VERR_INVALID_HANDLE);
RTTestErrorInc(pTest);
int cch = 0;
if (pTest->enmMaxLevel >= RTTESTLVL_FAILURE)
{
va_list va2;
va_copy(va2, va);
const char *pszEnd = strchr(pszFormat, '\0');
bool fHasNewLine = pszFormat != pszEnd
&& pszEnd[-1] == '\n';
RTCritSectEnter(&pTest->OutputLock);
cch += rtTestPrintf(pTest, fHasNewLine ? "%N" : "%N\n", pszFormat, &va2);
RTCritSectLeave(&pTest->OutputLock);
va_end(va2);
}
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.
*/
RTR3DECL(int) RTTestFailed(RTTEST hTest, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int cch = RTTestFailedV(hTest, pszFormat, va);
va_end(va);
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.
*/
RTR3DECL(int) RTTestFailureDetailsV(RTTEST hTest, const char *pszFormat, va_list va)
{
return RTTestPrintfV(hTest, RTTESTLVL_FAILURE, pszFormat, va);
}
/**
* 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.
*/
RTR3DECL(int) RTTestFailureDetails(RTTEST hTest, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int cch = RTTestFailureDetailsV(hTest, pszFormat, va);
va_end(va);
return cch;
}