/* $Id: cpl_test.h,v 1.16 2008/02/26 09:50:42 yjung Exp $ * * This file is part of the ESO Common Pipeline Library * Copyright (C) 2001-2004 European Southern Observatory * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * $Author: yjung $ * $Date: 2008/02/26 09:50:42 $ * $Revision: 1.16 $ * $Name: $ */ #ifndef CPL_TEST_H #define CPL_TEST_H /*----------------------------------------------------------------------------- Includes -----------------------------------------------------------------------------*/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include /*----------------------------------------------------------------------------- Defines -----------------------------------------------------------------------------*/ #undef CPL_HAVE_GNUC_NONNULL #if defined __GNUC__ #if __GNUC__ > 3 || __GNUC__ == 3 && defined __GNUC_MINOR__ && __GNUC_MINOR__ > 2 #define CPL_HAVE_GNUC_NONNULL #endif #endif CPL_BEGIN_DECLS /*----------------------------------------------------------------------------*/ /** @ingroup cpl_test @brief Initialize CPL + CPL messaging + unit test @param REPORT The email address for the error message e.g. PACKAGE_BUGREPORT @param LEVEL The default messaging level, e.g. CPL_MSG_WARNING @return void @see cpl_init() @note This macro should be used at the beginning of main() of a unit test instead of cpl_init() and before any other CPL function call. */ /*----------------------------------------------------------------------------*/ #define cpl_test_init(REPORT, LEVEL) \ cpl_test_init_macro(__FILE__, REPORT, LEVEL) /*----------------------------------------------------------------------------*/ /** @ingroup cpl_test @brief Evaluate an expression and increment an internal counter if zero @param bool The expression to evaluate, side-effects are allowed @note A zero value of the expression is a failure, other values are not @return void @see cpl_test_init() @note This macro should be used for unit tests Example of usage: @code cpl_test(myfunc()); // myfunc() is expected to return non-zero @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test(bool) cpl_test_macro((int)(bool), CPL_TRUE, #bool, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @ingroup cpl_test @brief Evaluate an expression and increment an internal counter if non-zero @param zero The numerical expression to evaluate, side-effects are allowed @note A zero value of the expression is a success, other values are not @return void @see cpl_test() @note This macro should be used for unit tests Example of usage: @code cpl_test_zero(myfunc()); // myfunc() is expected to return zero @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_zero(zero) cpl_test_macro((int)(zero), CPL_FALSE, #zero, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if a pointer is NULL and update an internal counter on failure @param pointer The NULL-pointer to check, side-effects are allowed @see cpl_test() @return void Example of usage: @code cpl_test_null(pointer); // pointer is expected to be NULL @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_null(pointer) \ cpl_test_null_macro(pointer, #pointer, cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if a pointer is non-NULL @param pointer The pointer to check, side-effects are allowed @see cpl_test_nonnull() @return void Example of usage: @code cpl_test_nonnull(pointer); // pointer is expected to be non-NULL @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_nonnull(pointer) \ cpl_test_nonnull_macro(pointer, #pointer, cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test and reset the CPL error code @param error The expected CPL error code (incl. CPL_ERROR_NONE) @see cpl_test() @note After the test, the CPL errorstate is reset @return void Example of usage: @code cpl_test( my_func(NULL) ); // my_func(NULL) is expected to return non-zero cpl_test_error(CPL_ERROR_NULL_INPUT); // ... and to set this error code // The errorstate has been reset. cpl_test( !my_func(p) ); // my_func(p) is expected to return zero @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_error(error) \ cpl_test_error_macro(error, #error, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if two integer expressions are equal @param first The first value in the comparison, side-effects are allowed @param second The second value in the comparison, side-effects are allowed @see cpl_test() @return void Example of usage: @code cpl_test_eq(computed, expected); @endcode For comparison of floating point values, see cpl_test_abs() and cpl_test_rel(). */ /*----------------------------------------------------------------------------*/ #define cpl_test_eq(first, second) \ cpl_test_eq_macro(first, #first, second, #second, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if two integer expressions are not equal @param first The first value in the comparison, side-effects are allowed @param second The second value in the comparison, side-effects are allowed @see cpl_test_eq() @return void Example of usage: @code cpl_test_noneq(computed, wrong); @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_noneq(first, second) \ cpl_test_noneq_macro(first, #first, second, #second, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if two strings are equal @param first The first string or NULL of the comparison @param second The second string or NULL of the comparison @note One or two NULL pointer(s) is considered a failure. Example of usage: @code cpl_test_eq_string(computed, expected); @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_eq_string(first, second) \ cpl_test_eq_string_macro(first, #first, second, #second, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @ingroup cpl_test @brief Evaluate A <= B and increment an internal counter if it is not true @param value The number to test @param tolerance The upper limit to compare against @return void @see cpl_test_init() @note This macro should be used for unit tests Example of usage: @code cpl_test_leq(fabs(myfunc(&p)), DBL_EPSILON); cpl_test(p != NULL); @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_leq(value, tolerance) \ cpl_test_leq_macro(value, tolerance, cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if two numerical expressions are within a given absolute tolerance @param first The first value in the comparison, side-effects are allowed @param second The second value in the comparison, side-effects are allowed @param tolerance A non-negative tolerance @note If the tolerance is negative, the test will always fail @see cpl_test() @return void Example of usage: @code cpl_test_abs(computed, expected, DBL_EPSILON); @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_abs(first, second, tolerance) \ cpl_test_abs_macro(first, #first, second, #second, \ tolerance, #tolerance, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if two numerical expressions are within a given relative tolerance @param first The first value in the comparison, side-effects are allowed @param second The second value in the comparison, side-effects are allowed @param tolerance A non-negative tolerance @note If the tolerance is negative or if one but not both of the two values is zero, the test will always fail. if both values are zero, the test will succeed for any non-negative tolerance. The test is commutative in the two values. @see cpl_test() @return void The test is carried out by comparing the absolute value of the difference abs (@em first - @em second) to the product of the tolerance and the minimum of the absolute value of the two values, tolerance * min(abs(@em first), abs(@em second)) (The test is implemented like this to avoid division with a number that may be zero. Example of usage: @code cpl_test_rel(computed, expected, 0.001); @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_test_rel(first, second, tolerance) \ cpl_test_rel_macro(first, #first, second, #second, \ tolerance, #tolerance, \ cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @brief Test if the memory system is empty @see cpl_memory_is_empty() */ /*----------------------------------------------------------------------------*/ #define cpl_test_memory_is_empty() \ cpl_test_memory_is_empty_macro(cpl_func, __FILE__, __LINE__) /*----------------------------------------------------------------------------*/ /** @ingroup cpl_test @brief Evaluate an expression and return if it fails @param bool The (boolean) expression to evaluate, side-effects are allowed @note A zero value of the expression is a failure, other values are not @return void @see cpl_test() @note This macro should be used for unit tests that cannot continue after a failure. Example of usage: @code int main (void) { cpl_test_init(CPL_MSG_WARNING); cpl_test(myfunc(&p)); cpl_assert(p != NULL); return cpl_test_end(0); } @endcode */ /*----------------------------------------------------------------------------*/ #define cpl_assert(bool) do { \ /* Evaluate bool just once */ \ const cpl_boolean cpl_assert_ok = (bool) ? CPL_TRUE : CPL_FALSE; \ cpl_test(cpl_assert_ok); \ if (cpl_assert_ok == CPL_FALSE) return cpl_test_end(1); \ } while (0) /* Acceptable error margin */ /* Should be set to 1.0 in development, can be set to 2.0 in deliveries */ #ifndef cpl_error_margin #define cpl_error_margin 2.0 #endif /*----------------------------------------------------------------------------- Function prototypes -----------------------------------------------------------------------------*/ void cpl_test_init_macro(const char *, const char *, cpl_msg_severity) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; int cpl_test_end(int); void cpl_test_macro(int, cpl_boolean, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_error_macro(cpl_error_code, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_null_macro(const void *, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull(2, 3, 4))) #endif ; void cpl_test_nonnull_macro(const void *, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull(2, 3, 4))) #endif ; void cpl_test_eq_macro(int, const char *, int, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_noneq_macro(int, const char *, int, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_eq_string_macro(const char *, const char *, const char *, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull(2, 4, 5, 6))) #endif ; void cpl_test_leq_macro(double, double, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_abs_macro(double, const char *, double, const char *, double, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_rel_macro(double, const char *, double, const char *, double, const char *, const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; void cpl_test_memory_is_empty_macro(const char *, const char *, unsigned) #ifdef CPL_HAVE_GNUC_NONNULL __attribute__((nonnull)) #endif ; CPL_END_DECLS #endif