/** @file * IPRT - Testcase Framework. */ /* * Copyright (C) 2009-2020 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 IPRT_INCLUDED_test_h #define IPRT_INCLUDED_test_h #ifndef RT_WITHOUT_PRAGMA_ONCE # pragma once #endif #include #include #include #include RT_C_DECLS_BEGIN /** @defgroup grp_rt_test RTTest - Testcase Framework. * @ingroup grp_rt * @{ */ /** A test handle. */ typedef R3PTRTYPE(struct RTTESTINT *) RTTEST; /** A pointer to a test handle. */ typedef RTTEST *PRTTEST; /** A const pointer to a test handle. */ typedef RTTEST const *PCRTTEST; /** A NIL Test handle. */ #define NIL_RTTEST ((RTTEST)0) /** * Test message importance level. */ typedef enum RTTESTLVL { /** Invalid 0. */ RTTESTLVL_INVALID = 0, /** Message should always be printed. */ RTTESTLVL_ALWAYS, /** Failure message. */ RTTESTLVL_FAILURE, /** Sub-test banner. */ RTTESTLVL_SUB_TEST, /** Info message. */ RTTESTLVL_INFO, /** Debug message. */ RTTESTLVL_DEBUG, /** The last (invalid). */ RTTESTLVL_END } RTTESTLVL; /** * Creates a test instance. * * @returns IPRT status code. * @param pszTest The test name. * @param phTest Where to store the test instance handle. */ RTR3DECL(int) RTTestCreate(const char *pszTest, PRTTEST phTest); /** * Creates a test instance for a child process. * * This differs from RTTestCreate in that it disabled result reporting to file * and pipe in order to avoid producing invalid XML. * * @returns IPRT status code. * @param pszTest The test name. * @param phTest Where to store the test instance handle. */ RTR3DECL(int) RTTestCreateChild(const char *pszTest, PRTTEST phTest); /** @name RTTEST_C_XXX - Flags for RTTestCreateEx. * @{ */ /** Whether to check the IPRT_TEST_XXX variables when constructing the * instance. The following environment variables get checks: * * - IPRT_TEST_MAX_LEVEL: String value indicating which level. * The env. var. is applied if the program specified the default level * (by passing RTTESTLVL_INVALID). * * - IPRT_TEST_PIPE: The native pipe/fifo handle to write XML * results to. * The env. var. is applied if iNativeTestPipe is -1. * * - IPRT_TEST_FILE: Path to file/named-pipe/fifo/whatever to * write XML results to. * The env. var. is applied if the program specified a NULL path, it is * not applied if the program hands us an empty string. * * - IPRT_TEST_OMIT_TOP_TEST: If present, this makes the XML output omit * the top level test element. * The env. var is applied when present. * */ #define RTTEST_C_USE_ENV RT_BIT(0) /** Whether to omit the top test in the XML. */ #define RTTEST_C_XML_OMIT_TOP_TEST RT_BIT(1) /** Whether to delay the top test XML element until testing commences. */ #define RTTEST_C_XML_DELAY_TOP_TEST RT_BIT(2) /** Whether to try install the test instance in the test TLS slot. Setting * this flag is incompatible with using the RTTestIXxxx variant of the API. */ #define RTTEST_C_NO_TLS RT_BIT(3) /** Don't report to the pipe (IPRT_TEST_PIPE or other). */ #define RTTEST_C_NO_XML_REPORTING_PIPE RT_BIT(4) /** Don't report to the results file (IPRT_TEST_FILE or other). */ #define RTTEST_C_NO_XML_REPORTING_FILE RT_BIT(4) /** No XML reporting to pipes, file or anything. * Child processes may want to use this so they don't garble the output of * the main test process. */ #define RTTEST_C_NO_XML_REPORTING (RTTEST_C_NO_XML_REPORTING_PIPE | RTTEST_C_NO_XML_REPORTING_FILE) /** Mask containing the valid bits. */ #define RTTEST_C_VALID_MASK UINT32_C(0x0000003f) /** @} */ /** * Creates a test instance. * * @returns IPRT status code. * @param pszTest The test name. * @param fFlags Flags, see RTTEST_C_XXX. * @param enmMaxLevel The max message level. Use RTTESTLVL_INVALID for * the default output level or one from the * environment. If specified, the environment variable * will not be able to override it. * @param iNativeTestPipe Native handle to a test pipe. -1 if not interested. * @param pszXmlFile The XML output file name. If NULL the environment * may be used. To selectively avoid that, pass an * empty string. * @param phTest Where to store the test instance handle. * * @note At the moment, we don't fail if @a pszXmlFile or @a iNativeTestPipe * fails to open. This may change later. */ RTR3DECL(int) RTTestCreateEx(const char *pszTest, uint32_t fFlags, RTTESTLVL enmMaxLevel, RTHCINTPTR iNativeTestPipe, const char *pszXmlFile, PRTTEST phTest); /** * Initializes IPRT and creates a test instance. * * Typical usage is: * @code int main(int argc, char **argv) { RTTEST hTest; int rc = RTTestInitAndCreate("tstSomething", &hTest); if (rc) return rc; ... } @endcode * * @returns RTEXITCODE_SUCCESS on success. On failure an error message is * printed and a suitable exit code is return. * * @param pszTest The test name. * @param phTest Where to store the test instance handle. */ RTR3DECL(RTEXITCODE) RTTestInitAndCreate(const char *pszTest, PRTTEST phTest); /** * Variant of RTTestInitAndCreate that includes IPRT init flags and argument * vectors. * * @returns RTEXITCODE_SUCCESS on success. On failure an error message is * printed and a suitable exit code is return. * * @param cArgs Pointer to the argument count. * @param ppapszArgs Pointer to the argument vector pointer. * @param fRtInit Flags, see RTR3INIT_XXX. * @param pszTest The test name. * @param phTest Where to store the test instance handle. */ RTR3DECL(RTEXITCODE) RTTestInitExAndCreate(int cArgs, char ***ppapszArgs, uint32_t fRtInit, const char *pszTest, PRTTEST phTest); /** * Destroys a test instance previously created by RTTestCreate. * * @returns IPRT status code. * @param hTest The test handle. NIL_RTTEST is ignored. */ RTR3DECL(int) RTTestDestroy(RTTEST hTest); /** * Changes the default test instance for the calling thread. * * @returns IPRT status code. * * @param hNewDefaultTest The new default test. NIL_RTTEST is fine. * @param phOldTest Where to store the old test handle. Optional. */ RTR3DECL(int) RTTestSetDefault(RTTEST hNewDefaultTest, PRTTEST phOldTest); /** * Changes the test case name. * * @returns IRPT status code. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param pszName The new test case name. Empty string is not accepted, * nor are strings longer than 127 chars. Keep it short * but descriptive. */ RTR3DECL(int) RTTestChangeName(RTTEST hTest, const char *pszName); /** * Allocate a block of guarded memory. * * @returns IPRT status code. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param cb The amount of memory to allocate. * @param cbAlign The alignment of the returned block. * @param fHead Head or tail optimized guard. * @param ppvUser Where to return the pointer to the block. */ RTR3DECL(int) RTTestGuardedAlloc(RTTEST hTest, size_t cb, uint32_t cbAlign, bool fHead, void **ppvUser); /** * Allocates a block of guarded memory where the guarded is immediately after * the user memory. * * @returns Pointer to the allocated memory. NULL on failure. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param cb The amount of memory to allocate. */ RTR3DECL(void *) RTTestGuardedAllocTail(RTTEST hTest, size_t cb); /** * Allocates a block of guarded memory where the guarded is right in front of * the user memory. * * @returns Pointer to the allocated memory. NULL on failure. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param cb The amount of memory to allocate. */ RTR3DECL(void *) RTTestGuardedAllocHead(RTTEST hTest, size_t cb); /** * Frees a block of guarded memory. * * @returns IPRT status code. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param pv The memory. NULL is ignored. */ RTR3DECL(int) RTTestGuardedFree(RTTEST hTest, void *pv); /** * 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) RT_IPRT_FORMAT_ATTR(3, 0); /** * 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, ...) RT_IPRT_FORMAT_ATTR(3, 4); /** * 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) RT_IPRT_FORMAT_ATTR(3, 0); /** * 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, ...) RT_IPRT_FORMAT_ATTR(3, 4); /** * 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); /** * 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); /** * Skips 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. * @param pszReasonFmt Text explaining why, optional (NULL). * @param va Arguments for the reason format string. */ RTR3DECL(RTEXITCODE) RTTestSkipAndDestroyV(RTTEST hTest, const char *pszReasonFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); /** * Skips 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. * @param pszReasonFmt Text explaining why, optional (NULL). * @param ... Arguments for the reason format string. */ RTR3DECL(RTEXITCODE) RTTestSkipAndDestroy(RTTEST hTest, const char *pszReasonFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * 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); /** * 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, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * 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 va Arguments. */ RTR3DECL(int) RTTestSubV(RTTEST hTest, const char *pszSubTestFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); /** * Completes a sub-test. * * @returns Number of chars printed, negative numbers are IPRT error codes. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. */ RTR3DECL(int) RTTestSubDone(RTTEST hTest); /** * 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 Number of chars printed, negative numbers are IPRT error codes. * @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) RT_IPRT_FORMAT_ATTR(2, 0); /** * Prints an extended PASSED message, optional. * * This does not conclude the sub-test, it could be used to report the passing * of a sub-sub-to-the-power-of-N-test. * * @returns Number of chars printed, negative numbers are IPRT error codes. * @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, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * Marks the current test as 'SKIPPED' and optionally displays a message * explaining why. * * @returns Number of chars printed, negative numbers are IPRT error codes. * @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. Can be NULL or empty. * @param ... The arguments. */ RTR3DECL(int) RTTestSkipped(RTTEST hTest, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(2, 3); /** * Marks the current test as 'SKIPPED' and optionally displays a message * explaining why. * * @returns Number of chars printed, negative numbers are IPRT error codes. * @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. Can be NULL or empty. * @param va The arguments. */ RTR3DECL(int) RTTestSkippedV(RTTEST hTest, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(2, 0); /** * Value units. * * @remarks This is an interface where we have to be binary compatible with both * older versions of this header and other components using the same * contant values. * @remarks When adding a new item: * - Always add at the end of the list - do NOT group it. * - Add it to rtTestUnitName in r3/test.cpp. * - include/VBox/VMMDevTesting.h (VMMDEV_TESTING_UNIT_XXX). * - Add it to g_aszBs2TestUnitNames in * TestSuite/bootsectors/bootsector2-common-routines.mac. * */ typedef enum RTTESTUNIT { /** The customary invalid zero value. */ RTTESTUNIT_INVALID = 0, RTTESTUNIT_PCT, /**< Percentage (10^-2). */ RTTESTUNIT_BYTES, /**< Bytes. */ RTTESTUNIT_BYTES_PER_SEC, /**< Bytes per second. */ RTTESTUNIT_KILOBYTES, /**< Kilobytes. */ RTTESTUNIT_KILOBYTES_PER_SEC, /**< Kilobytes per second. */ RTTESTUNIT_MEGABYTES, /**< Megabytes. */ RTTESTUNIT_MEGABYTES_PER_SEC, /**< Megabytes per second. */ RTTESTUNIT_PACKETS, /**< Packets. */ RTTESTUNIT_PACKETS_PER_SEC, /**< Packets per second. */ RTTESTUNIT_FRAMES, /**< Frames. */ RTTESTUNIT_FRAMES_PER_SEC, /**< Frames per second. */ RTTESTUNIT_OCCURRENCES, /**< Occurrences. */ RTTESTUNIT_OCCURRENCES_PER_SEC, /**< Occurrences per second. */ RTTESTUNIT_CALLS, /**< Calls. */ RTTESTUNIT_CALLS_PER_SEC, /**< Calls per second. */ RTTESTUNIT_ROUND_TRIP, /**< Round trips. */ RTTESTUNIT_SECS, /**< Seconds. */ RTTESTUNIT_MS, /**< Milliseconds. */ RTTESTUNIT_NS, /**< Nanoseconds. */ RTTESTUNIT_NS_PER_CALL, /**< Nanoseconds per call. */ RTTESTUNIT_NS_PER_FRAME, /**< Nanoseconds per frame. */ RTTESTUNIT_NS_PER_OCCURRENCE, /**< Nanoseconds per occurrence. */ RTTESTUNIT_NS_PER_PACKET, /**< Nanoseconds per frame. */ RTTESTUNIT_NS_PER_ROUND_TRIP, /**< Nanoseconds per round trip. */ RTTESTUNIT_INSTRS, /**< Instructions. */ RTTESTUNIT_INSTRS_PER_SEC, /**< Instructions per second. */ RTTESTUNIT_NONE, /**< No unit. */ RTTESTUNIT_PP1K, /**< Parts per thousand (10^-3). */ RTTESTUNIT_PP10K, /**< Parts per ten thousand (10^-4). */ RTTESTUNIT_PPM, /**< Parts per million (10^-6). */ RTTESTUNIT_PPB, /**< Parts per billion (10^-9). */ /** The end of valid units. */ RTTESTUNIT_END } RTTESTUNIT; AssertCompile(RTTESTUNIT_INSTRS == 0x19); AssertCompile(RTTESTUNIT_NONE == 0x1b); /** * Report a named test result value. * * This is typically used for benchmarking but can be used for other purposes * like reporting limits of some implementation. The value gets associated with * the current sub test, the name must be unique within the sub test. * * @returns IPRT status code. * * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param pszName The value name. * @param u64Value The value. * @param enmUnit The value unit. */ RTR3DECL(int) RTTestValue(RTTEST hTest, const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit); /** * Same as RTTestValue, except that the name is now a format string. * * @returns IPRT status code. * * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param u64Value The value. * @param enmUnit The value unit. * @param pszNameFmt The value name format string. * @param ... String arguments. */ RTR3DECL(int) RTTestValueF(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(4, 5); /** * Same as RTTestValue, except that the name is now a format string. * * @returns IPRT status code. * * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @param u64Value The value. * @param enmUnit The value unit. * @param pszNameFmt The value name format string. * @param va String arguments. */ RTR3DECL(int) RTTestValueV(RTTEST hTest, uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(4, 0); /** * 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); /** * 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); /** * Get the error count of the current sub test. * * @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) RTTestSubErrorCount(RTTEST hTest); /** * 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) RT_IPRT_FORMAT_ATTR(2, 0); /** * 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, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * 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) RT_IPRT_FORMAT_ATTR(2, 0); /** * 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, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * Disables and shuts up assertions. * * Max 8 nestings. * * @returns IPRT status code. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. * @sa RTAssertSetMayPanic, RTAssertSetQuiet. */ RTR3DECL(int) RTTestDisableAssertions(RTTEST hTest); /** * Restores the previous call to RTTestDisableAssertions. * * @returns IPRT status code. * @param hTest The test handle. If NIL_RTTEST we'll use the one * associated with the calling thread. */ RTR3DECL(int) RTTestRestoreAssertions(RTTEST hTest); /** @def RTTEST_CHECK * Check whether a boolean expression holds true. * * If the expression is false, call RTTestFailed giving the line number and expression. * * @param hTest The test handle. * @param expr The expression to evaluate. */ #define RTTEST_CHECK(hTest, expr) \ do { if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ } \ } while (0) /** @def RTTEST_CHECK_RET * Check whether a boolean expression holds true, returns on false. * * If the expression is false, call RTTestFailed giving the line number and * expression, then return @a rcRet. * * @param hTest The test handle. * @param expr The expression to evaluate. * @param rcRet What to return on failure. */ #define RTTEST_CHECK_RET(hTest, expr, rcRet) \ do { if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ return (rcRet); \ } \ } while (0) /** @def RTTEST_CHECK_RETV * Check whether a boolean expression holds true, returns void on false. * * If the expression is false, call RTTestFailed giving the line number and * expression, then return void. * * @param hTest The test handle. * @param expr The expression to evaluate. */ #define RTTEST_CHECK_RETV(hTest, expr) \ do { if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ return; \ } \ } while (0) /** @def RTTEST_CHECK_BREAK * Check whether a boolean expression holds true. * * If the expression is false, call RTTestFailed giving the line number and * expression, then break. * * @param hTest The test handle. * @param expr The expression to evaluate. */ #define RTTEST_CHECK_BREAK(hTest, expr) \ if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ break; \ } else do {} while (0) /** @def RTTEST_CHECK_MSG * Check whether a boolean expression holds true. * * If the expression is false, call RTTestFailed giving the line number and expression. * * @param hTest The test handle. * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestFailureDetails, including * parenthesis. */ #define RTTEST_CHECK_MSG(hTest, expr, DetailsArgs) \ do { if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ RTTestFailureDetails DetailsArgs; \ } \ } while (0) /** @def RTTEST_CHECK_MSG_RET * Check whether a boolean expression holds true, returns on false. * * If the expression is false, call RTTestFailed giving the line number and expression. * * @param hTest The test handle. * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestFailureDetails, including * parenthesis. * @param rcRet What to return on failure. */ #define RTTEST_CHECK_MSG_RET(hTest, expr, DetailsArgs, rcRet) \ do { if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ RTTestFailureDetails DetailsArgs; \ return (rcRet); \ } \ } while (0) /** @def RTTEST_CHECK_MSG_RETV * Check whether a boolean expression holds true, returns void on false. * * If the expression is false, call RTTestFailed giving the line number and expression. * * @param hTest The test handle. * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestFailureDetails, including * parenthesis. */ #define RTTEST_CHECK_MSG_RETV(hTest, expr, DetailsArgs) \ do { if (!(expr)) { \ RTTestFailed((hTest), "line %u: %s", __LINE__, #expr); \ RTTestFailureDetails DetailsArgs; \ return; \ } \ } while (0) /** @def RTTEST_CHECK_RC * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestFailed giving the line * number, expression, actual and expected status codes. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. */ #define RTTEST_CHECK_RC(hTest, rcExpr, rcExpect) \ do { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ } \ } while (0) /** @def RTTEST_CHECK_RC_RET * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestFailed giving the line * number, expression, actual and expected status codes, then return. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. * This will be assigned to a local rcCheck variable * that can be used as return value. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. * @param rcRet The return code. */ #define RTTEST_CHECK_RC_RET(hTest, rcExpr, rcExpect, rcRet) \ do { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ return (rcRet); \ } \ } while (0) /** @def RTTEST_CHECK_RC_RETV * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestFailed giving the line * number, expression, actual and expected status codes, then return. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. */ #define RTTEST_CHECK_RC_RETV(hTest, rcExpr, rcExpect) \ do { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ return; \ } \ } while (0) /** @def RTTEST_CHECK_RC_BREAK * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestFailed giving the line * number, expression, actual and expected status codes, then break. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. */ #define RTTEST_CHECK_RC_BREAK(hTest, rcExpr, rcExpect) \ if (1) { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestFailed((hTest), "line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ break; \ } \ } else do {} while (0) /** @def RTTEST_CHECK_RC_OK * Check whether a IPRT style status code indicates success. * * If the status indicates failure, call RTTestFailed giving the line number, * expression and status code. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. */ #define RTTEST_CHECK_RC_OK(hTest, rcExpr) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ } \ } while (0) /** @def RTTEST_CHECK_RC_OK_RET * Check whether a IPRT style status code indicates success. * * If the status indicates failure, call RTTestFailed giving the line number, * expression and status code, then return with the specified value. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. * This will be assigned to a local rcCheck variable * that can be used as return value. * @param rcRet The return code. */ #define RTTEST_CHECK_RC_OK_RET(hTest, rcExpr, rcRet) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ return (rcRet); \ } \ } while (0) /** @def RTTEST_CHECK_RC_OK_RETV * Check whether a IPRT style status code indicates success. * * If the status indicates failure, call RTTestFailed giving the line number, * expression and status code, then return. * * @param hTest The test handle. * @param rcExpr The expression resulting in an IPRT status code. */ #define RTTEST_CHECK_RC_OK_RETV(hTest, rcExpr) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestFailed((hTest), "line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ return; \ } \ } while (0) /** @name Implicit Test Handle API Variation * The test handle is retrieved from the test TLS entry of the calling thread. * @{ */ /** * Test vprintf, makes sure lines are prefixed and so forth. * * @returns Number of chars printed. * @param enmLevel Message importance level. * @param pszFormat The message. * @param va Arguments. */ RTR3DECL(int) RTTestIPrintfV(RTTESTLVL enmLevel, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); /** * Test printf, makes sure lines are prefixed and so forth. * * @returns Number of chars printed. * @param enmLevel Message importance level. * @param pszFormat The message. * @param ... Arguments. */ RTR3DECL(int) RTTestIPrintf(RTTESTLVL enmLevel, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * 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 pszSubTest The sub-test name. */ RTR3DECL(int) RTTestISub(const char *pszSubTest); /** * Format string version of RTTestSub. * * See RTTestSub for details. * * @returns Number of chars printed. * @param pszSubTestFmt The sub-test name format string. * @param ... Arguments. */ RTR3DECL(int) RTTestISubF(const char *pszSubTestFmt, ...) RT_IPRT_FORMAT_ATTR(1, 2); /** * Format string version of RTTestSub. * * See RTTestSub for details. * * @returns Number of chars printed. * @param pszSubTestFmt The sub-test name format string. * @param va Arguments. */ RTR3DECL(int) RTTestISubV(const char *pszSubTestFmt, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); /** * Completes a sub-test. * * @returns Number of chars printed. */ RTR3DECL(int) RTTestISubDone(void); /** * 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 pszFormat The message. No trailing newline. * @param va The arguments. */ RTR3DECL(int) RTTestIPassedV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); /** * Prints an extended PASSED message, optional. * * This does not conclude the sub-test, it could be used to report the passing * of a sub-sub-to-the-power-of-N-test. * * @returns IPRT status code. * @param pszFormat The message. No trailing newline. * @param ... The arguments. */ RTR3DECL(int) RTTestIPassed(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); /** * Report a named test result value. * * This is typically used for benchmarking but can be used for other purposes * like reporting limits of some implementation. The value gets associated with * the current sub test, the name must be unique within the sub test. * * @returns IPRT status code. * * @param pszName The value name. * @param u64Value The value. * @param enmUnit The value unit. */ RTR3DECL(int) RTTestIValue(const char *pszName, uint64_t u64Value, RTTESTUNIT enmUnit); /** * Same as RTTestValue, except that the name is now a format string. * * @returns IPRT status code. * * @param u64Value The value. * @param enmUnit The value unit. * @param pszNameFmt The value name format string. * @param ... String arguments. */ RTR3DECL(int) RTTestIValueF(uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(3, 4); /** * Same as RTTestValue, except that the name is now a format string. * * @returns IPRT status code. * * @param u64Value The value. * @param enmUnit The value unit. * @param pszNameFmt The value name format string. * @param va String arguments. */ RTR3DECL(int) RTTestIValueV(uint64_t u64Value, RTTESTUNIT enmUnit, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); /** * Increments the error counter. * * @returns IPRT status code. */ RTR3DECL(int) RTTestIErrorInc(void); /** * Get the current error count. * * @returns The error counter, UINT32_MAX if no valid test handle. */ RTR3DECL(uint32_t) RTTestIErrorCount(void); /** * Increments the error counter and prints a failure message. * * @returns IPRT status code. * @param pszFormat The message. No trailing newline. * @param va The arguments. */ RTR3DECL(int) RTTestIFailedV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); /** * Increments the error counter and prints a failure message. * * @returns IPRT status code. * @param pszFormat The message. No trailing newline. * @param ... The arguments. */ RTR3DECL(int) RTTestIFailed(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); /** * Increments the error counter, prints a failure message and returns the * specified status code. * * This is mainly a convenience method for saving vertical space in the source * code. * * @returns @a rcRet * @param rcRet The IPRT status code to return. * @param pszFormat The message. No trailing newline. * @param va The arguments. */ RTR3DECL(int) RTTestIFailedRcV(int rcRet, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); /** * Increments the error counter, prints a failure message and returns the * specified status code. * * This is mainly a convenience method for saving vertical space in the source * code. * * @returns @a rcRet * @param rcRet The IPRT status code to return. * @param pszFormat The message. No trailing newline. * @param ... The arguments. */ RTR3DECL(int) RTTestIFailedRc(int rcRet, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); /** * Same as RTTestIPrintfV with RTTESTLVL_FAILURE. * * @returns Number of chars printed. * @param pszFormat The message. * @param va Arguments. */ RTR3DECL(int) RTTestIFailureDetailsV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); /** * Same as RTTestIPrintf with RTTESTLVL_FAILURE. * * @returns Number of chars printed. * @param pszFormat The message. * @param ... Arguments. */ RTR3DECL(int) RTTestIFailureDetails(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); /** * Disables and shuts up assertions. * * Max 8 nestings. * * @returns IPRT status code. * @sa RTAssertSetMayPanic, RTAssertSetQuiet. */ RTR3DECL(int) RTTestIDisableAssertions(void); /** * Restores the previous call to RTTestDisableAssertions. * * @returns IPRT status code. */ RTR3DECL(int) RTTestIRestoreAssertions(void); /** @def RTTESTI_CHECK * Check whether a boolean expression holds true. * * If the expression is false, call RTTestIFailed giving the line number and * expression. * * @param expr The expression to evaluate. */ #define RTTESTI_CHECK(expr) \ do { if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ } \ } while (0) /** @def RTTESTI_CHECK_RET * Check whether a boolean expression holds true, returns on false. * * If the expression is false, call RTTestIFailed giving the line number and * expression, then return @a rcRet. * * @param expr The expression to evaluate. * @param rcRet What to return on failure. */ #define RTTESTI_CHECK_RET(expr, rcRet) \ do { if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ return (rcRet); \ } \ } while (0) /** @def RTTESTI_CHECK_RETV * Check whether a boolean expression holds true, returns void on false. * * If the expression is false, call RTTestIFailed giving the line number and * expression, then return void. * * @param expr The expression to evaluate. */ #define RTTESTI_CHECK_RETV(expr) \ do { if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ return; \ } \ } while (0) /** @def RTTESTI_CHECK_BREAK * Check whether a boolean expression holds true, returns void on false. * * If the expression is false, call RTTestIFailed giving the line number and * expression, then break. * * @param expr The expression to evaluate. */ #define RTTESTI_CHECK_BREAK(expr) \ if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ break; \ } else do {} while (0) /** @def RTTESTI_CHECK_MSG * Check whether a boolean expression holds true. * * If the expression is false, call RTTestIFailed giving the line number and * expression. * * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestIFailureDetails, including * parenthesis. */ #define RTTESTI_CHECK_MSG(expr, DetailsArgs) \ do { if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ RTTestIFailureDetails DetailsArgs; \ } \ } while (0) /** @def RTTESTI_CHECK_MSG_BREAK * Check whether a boolean expression holds true, returns on false. * * If the expression is false, call RTTestIFailed giving the line number and * expression. * * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestIFailureDetails, including * parenthesis. */ #define RTTESTI_CHECK_MSG_BREAK(expr, DetailsArgs) \ if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ RTTestIFailureDetails DetailsArgs; \ break; \ } else do {} while (0) /** @def RTTESTI_CHECK_MSG_RET * Check whether a boolean expression holds true, returns on false. * * If the expression is false, call RTTestIFailed giving the line number and * expression. * * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestIFailureDetails, including * parenthesis. * @param rcRet What to return on failure. */ #define RTTESTI_CHECK_MSG_RET(expr, DetailsArgs, rcRet) \ do { if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ RTTestIFailureDetails DetailsArgs; \ return (rcRet); \ } \ } while (0) /** @def RTTESTI_CHECK_MSG_RETV * Check whether a boolean expression holds true, returns void on false. * * If the expression is false, call RTTestIFailed giving the line number and * expression. * * @param expr The expression to evaluate. * @param DetailsArgs Argument list for RTTestIFailureDetails, including * parenthesis. */ #define RTTESTI_CHECK_MSG_RETV(expr, DetailsArgs) \ do { if (!(expr)) { \ RTTestIFailed("line %u: %s", __LINE__, #expr); \ RTTestIFailureDetails DetailsArgs; \ return; \ } \ } while (0) /** @def RTTESTI_CHECK_RC * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestIFailed giving the line * number, expression, actual and expected status codes. * * @param rcExpr The expression resulting in an IPRT status code. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. */ #define RTTESTI_CHECK_RC(rcExpr, rcExpect) \ do { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ } \ } while (0) /** @def RTTESTI_CHECK_RC_RET * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestIFailed giving the line * number, expression, actual and expected status codes, then return. * * @param rcExpr The expression resulting in an IPRT status code. * This will be assigned to a local rcCheck variable * that can be used as return value. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. * @param rcRet The return code. */ #define RTTESTI_CHECK_RC_RET(rcExpr, rcExpect, rcRet) \ do { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ return (rcRet); \ } \ } while (0) /** @def RTTESTI_CHECK_RC_RETV * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestIFailed giving the line * number, expression, actual and expected status codes, then return. * * @param rcExpr The expression resulting in an IPRT status code. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. */ #define RTTESTI_CHECK_RC_RETV(rcExpr, rcExpect) \ do { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ return; \ } \ } while (0) /** @def RTTESTI_CHECK_RC_BREAK * Check whether an expression returns a specific IPRT style status code. * * If a different status code is return, call RTTestIFailed giving the line * number, expression, actual and expected status codes, then break. * * @param rcExpr The expression resulting in an IPRT status code. * @param rcExpect The expected return code. This may be referenced * more than once by the macro. */ #define RTTESTI_CHECK_RC_BREAK(rcExpr, rcExpect) \ if (1) { \ int rcCheck = (rcExpr); \ if (rcCheck != (rcExpect)) { \ RTTestIFailed("line %u: %s: expected %Rrc, got %Rrc", __LINE__, #rcExpr, (rcExpect), rcCheck); \ break; \ } \ } else do {} while (0) /** @def RTTESTI_CHECK_RC_OK * Check whether a IPRT style status code indicates success. * * If the status indicates failure, call RTTestIFailed giving the line number, * expression and status code. * * @param rcExpr The expression resulting in an IPRT status code. */ #define RTTESTI_CHECK_RC_OK(rcExpr) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ } \ } while (0) /** @def RTTESTI_CHECK_RC_OK_BREAK * Check whether a IPRT style status code indicates success. * * If a different status code is return, call RTTestIFailed giving the line * number, expression, actual and expected status codes, then break. * * @param rcExpr The expression resulting in an IPRT status code. */ #define RTTESTI_CHECK_RC_OK_BREAK(rcExpr) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ break; \ } \ } while (0) /** @def RTTESTI_CHECK_RC_OK_RET * Check whether a IPRT style status code indicates success. * * If the status indicates failure, call RTTestIFailed giving the line number, * expression and status code, then return with the specified value. * * @param rcExpr The expression resulting in an IPRT status code. * This will be assigned to a local rcCheck variable * that can be used as return value. * @param rcRet The return code. */ #define RTTESTI_CHECK_RC_OK_RET(rcExpr, rcRet) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ return (rcRet); \ } \ } while (0) /** @def RTTESTI_CHECK_RC_OK_RETV * Check whether a IPRT style status code indicates success. * * If the status indicates failure, call RTTestIFailed giving the line number, * expression and status code, then return. * * @param rcExpr The expression resulting in an IPRT status code. */ #define RTTESTI_CHECK_RC_OK_RETV(rcExpr) \ do { \ int rcCheck = (rcExpr); \ if (RT_FAILURE(rcCheck)) { \ RTTestIFailed("line %u: %s: %Rrc", __LINE__, #rcExpr, rcCheck); \ return; \ } \ } while (0) /** @} */ /** @} */ RT_C_DECLS_END #endif /* !IPRT_INCLUDED_test_h */