From d063add7cbdaf82e6208ef01414432320260e974 Mon Sep 17 00:00:00 2001 From: Pauli Date: Thu, 13 Apr 2017 08:51:28 +1000 Subject: [PATCH] Guarantee single argument evaluation for test macros. Add test case that checks some of them. Reviewed-by: Richard Levitte Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/3208) --- test/README | 14 +++++++- test/test_test.c | 56 ++++++++++++++++++++++++++++++ test/testutil.h | 90 ++++++++++++++++++++++++++---------------------- 3 files changed, 117 insertions(+), 43 deletions(-) diff --git a/test/README b/test/README index cf7e4d4948..7831c860f5 100644 --- a/test/README +++ b/test/README @@ -134,4 +134,16 @@ conditions. These macros produce an error message in a standard format if the condition is not met (and nothing if the condition is met). Additional information can be presented with the TEST_info macro that takes a printf format string and arguments. TEST_error is useful for complicated conditions, -it also takes a printf format string and argument. +it also takes a printf format string and argument. In all cases the TEST_xxx +macros are guaranteed to evaluate their arguments exactly once. This means +that expressions with side effects are allowed as parameters. Thus, + + if (!TEST_ptr(ptr = OPENSSL_malloc(..))) + +works fine and can be used in place of: + + ptr = OPENSSL_malloc(..); + if (!TEST_ptr(ptr)) + +The former produces a more meaningful message on failure than the latter. + diff --git a/test/test_test.c b/test/test_test.c index df4725a7a4..a1542892e9 100644 --- a/test/test_test.c +++ b/test/test_test.c @@ -259,6 +259,61 @@ static int test_messages(void) return 1; } +static int test_single_eval(void) +{ + int i = 4; + long l = -9000; + char c = 'd'; + unsigned char uc = 22; + unsigned long ul = 500; + size_t st = 1234; + char buf[4] = { 0 }, *p = buf; + + /* int */ + return TEST_int_eq(i++, 4) + && TEST_int_eq(i, 5) + && TEST_int_gt(++i, 5) + && TEST_int_le(5, i++) + && TEST_int_ne(--i, 5) + && TEST_int_eq(12, i *= 2) + /* Long */ + && TEST_long_eq(l--, -9000L) + && TEST_long_eq(++l, -9000L) + && TEST_long_ne(-9000L, l /= 2) + && TEST_long_lt(--l, -4500L) + /* char */ + && TEST_char_eq(++c, 'e') + && TEST_char_eq('e', c--) + && TEST_char_ne('d', --c) + && TEST_char_le('b', --c) + && TEST_char_lt(c++, 'c') + /* unsigned char */ + && TEST_uchar_eq(22, uc++) + && TEST_uchar_eq(uc /= 2, 11) + && TEST_ulong_eq(ul ^= 1, 501) + && TEST_ulong_eq(502, ul ^= 3) + && TEST_ulong_eq(ul = ul * 3 - 6, 1500) + /* size_t */ + && TEST_size_t_eq((--i, st++), 1234) + && TEST_size_t_eq(st, 1235) + && TEST_int_eq(11, i) + /* pointers */ + && TEST_ptr_eq(p++, buf) + && TEST_ptr_eq(buf + 2, ++p) + && TEST_ptr_eq(buf, p -= 2) + && TEST_ptr(++p) + && TEST_ptr_eq(p, buf + 1) + && TEST_ptr_null(p = NULL) + /* strings */ + && TEST_str_eq(p = "123456" + 1, "23456") + && TEST_str_eq("3456", ++p) + && TEST_str_ne(p++, "456") + /* memory */ + && TEST_mem_eq(--p, sizeof("3456"), "3456", sizeof("3456")) + && TEST_mem_ne(p++, sizeof("456"), "456", sizeof("456")) + && TEST_mem_eq(p--, sizeof("456"), "456", sizeof("456")); +} + void register_tests(void) { ADD_TEST(test_int); @@ -273,4 +328,5 @@ void register_tests(void) ADD_TEST(test_string); ADD_TEST(test_memory); ADD_TEST(test_messages); + ADD_TEST(test_single_eval); } diff --git a/test/testutil.h b/test/testutil.h index a83323b9e8..0631a8b7f8 100644 --- a/test/testutil.h +++ b/test/testutil.h @@ -191,7 +191,7 @@ DECLARE_COMPARISON(char *, str, ne) /* * Equality test for memory blocks where NULL is a legitimate value. -* These calls return 1 if the two memory blocks compare true. + * These calls return 1 if the two memory blocks compare true. * Otherwise, they return 0 and pretty-print diagnostics. * These should not be called directly, use the TEST_xxx macros below instead. */ @@ -223,6 +223,12 @@ void test_info_c90(const char *desc, ...) PRINTF_FORMAT(1, 2); /* * The following macros provide wrapper calls to the test functions with * a default description that indicates the file and line number of the error. + * + * The following macros guarantee to evaluate each argument exactly once. + * This allows constructs such as: if(!TEST_ptr(ptr = OPENSSL_malloc(..))) + * to produce better contextual output than: + * ptr = OPENSSL_malloc(..); + * if (!TEST_ptr(ptr)) */ # define TEST_int_eq(a, b) test_int_eq(__FILE__, __LINE__, #a, #b, a, b) # define TEST_int_ne(a, b) test_int_ne(__FILE__, __LINE__, #a, #b, a, b) @@ -238,47 +244,47 @@ void test_info_c90(const char *desc, ...) PRINTF_FORMAT(1, 2); # define TEST_int_gt(a, b) test_int_gt(__FILE__, __LINE__, #a, #b, a, b) # define TEST_int_ge(a, b) test_int_ge(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uint_eq(a, b) test_uint_eq(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uint_ne(a, b) test_uint_ne(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uint_lt(a, b) test_uint_lt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uint_le(a, b) test_uint_le(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uint_gt(a, b) test_uint_gt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uint_ge(a, b) test_uint_ge(__FILE__, __LINE__, #a, #b, a, b) - -# define TEST_char_eq(a, b) test_char_eq(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_char_ne(a, b) test_char_ne(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_char_lt(a, b) test_char_lt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_char_le(a, b) test_char_le(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_char_gt(a, b) test_char_gt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_char_ge(a, b) test_char_ge(__FILE__, __LINE__, #a, #b, a, b) - -# define TEST_uchar_eq(a, b) test_uchar_eq(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uchar_ne(a, b) test_uchar_ne(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uchar_lt(a, b) test_uchar_lt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uchar_le(a, b) test_uchar_le(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uchar_gt(a, b) test_uchar_gt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_uchar_ge(a, b) test_uchar_ge(__FILE__, __LINE__, #a, #b, a, b) - -# define TEST_long_eq(a, b) test_long_eq(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_long_ne(a, b) test_long_ne(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_long_lt(a, b) test_long_lt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_long_le(a, b) test_long_le(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_long_gt(a, b) test_long_gt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_long_ge(a, b) test_long_ge(__FILE__, __LINE__, #a, #b, a, b) - -# define TEST_ulong_eq(a, b) test_ulong_eq(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_ulong_ne(a, b) test_ulong_ne(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_ulong_lt(a, b) test_ulong_lt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_ulong_le(a, b) test_ulong_le(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_ulong_gt(a, b) test_ulong_gt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_ulong_ge(a, b) test_ulong_ge(__FILE__, __LINE__, #a, #b, a, b) - -# define TEST_size_t_eq(a, b) test_size_t_eq(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_size_t_ne(a, b) test_size_t_ne(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_size_t_lt(a, b) test_size_t_lt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_size_t_le(a, b) test_size_t_le(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_size_t_gt(a, b) test_size_t_gt(__FILE__, __LINE__, #a, #b, a, b) -# define TEST_size_t_ge(a, b) test_size_t_ge(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uint_eq(a, b) test_uint_eq(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uint_ne(a, b) test_uint_ne(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uint_lt(a, b) test_uint_lt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uint_le(a, b) test_uint_le(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uint_gt(a, b) test_uint_gt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uint_ge(a, b) test_uint_ge(__FILE__, __LINE__, #a, #b, a, b) + +# define TEST_char_eq(a, b) test_char_eq(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_char_ne(a, b) test_char_ne(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_char_lt(a, b) test_char_lt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_char_le(a, b) test_char_le(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_char_gt(a, b) test_char_gt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_char_ge(a, b) test_char_ge(__FILE__, __LINE__, #a, #b, a, b) + +# define TEST_uchar_eq(a, b) test_uchar_eq(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uchar_ne(a, b) test_uchar_ne(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uchar_lt(a, b) test_uchar_lt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uchar_le(a, b) test_uchar_le(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uchar_gt(a, b) test_uchar_gt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_uchar_ge(a, b) test_uchar_ge(__FILE__, __LINE__, #a, #b, a, b) + +# define TEST_long_eq(a, b) test_long_eq(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_long_ne(a, b) test_long_ne(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_long_lt(a, b) test_long_lt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_long_le(a, b) test_long_le(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_long_gt(a, b) test_long_gt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_long_ge(a, b) test_long_ge(__FILE__, __LINE__, #a, #b, a, b) + +# define TEST_ulong_eq(a, b) test_ulong_eq(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_ulong_ne(a, b) test_ulong_ne(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_ulong_lt(a, b) test_ulong_lt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_ulong_le(a, b) test_ulong_le(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_ulong_gt(a, b) test_ulong_gt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_ulong_ge(a, b) test_ulong_ge(__FILE__, __LINE__, #a, #b, a, b) + +# define TEST_size_t_eq(a, b) test_size_t_eq(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_size_t_ne(a, b) test_size_t_ne(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_size_t_lt(a, b) test_size_t_lt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_size_t_le(a, b) test_size_t_le(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_size_t_gt(a, b) test_size_t_gt(__FILE__, __LINE__, #a, #b, a, b) +# define TEST_size_t_ge(a, b) test_size_t_ge(__FILE__, __LINE__, #a, #b, a, b) # define TEST_ptr_eq(a, b) test_ptr_eq(__FILE__, __LINE__, #a, #b, a, b) # define TEST_ptr_ne(a, b) test_ptr_ne(__FILE__, __LINE__, #a, #b, a, b) -- 2.34.1