diff --git a/doc/check.texi b/doc/check.texi index 7391aa98..3af9ada5 100644 --- a/doc/check.texi +++ b/doc/check.texi @@ -1204,6 +1204,16 @@ operator is again indicated by last two letters of the function name. of the character string @code{a} is less than that of @code{b}. If a NULL pointer would be passed to any comparison macro than check would fail. +@item ck_assert_pstr_eq +@itemx ck_assert_pstr_ne + +Similar to @code{ck_assert_str_*} macros, but able to check undefined strings. +If a NULL pointer would be passed to a comparison macro it would mean that +a string is undefined. If both strings are undefined @code{ck_assert_pstr_eq} +would pass, but @code{ck_assert_pstr_ne} would fail. If only one of strings is +undefined @code{ck_assert_pstr_eq} macro would fail and @code{ck_assert_pstr_ne} +would pass. + @item ck_assert_ptr_eq @itemx ck_assert_ptr_ne diff --git a/src/check.h.in b/src/check.h.in index 3b85facf..e78d6907 100644 --- a/src/check.h.in +++ b/src/check.h.in @@ -1487,6 +1487,46 @@ do { \ */ #define ck_assert_str_ge(X, Y) _ck_assert_str(X, >=, Y, 0, 0) +/** + * Check two strings to determine if 0==strcmp(X,Y) or if both are undefined + * + * If both X and Y are NULL the test passes. However, if only one is NULL + * the test fails. + * If not ((X==NULL)&&(Y==NULL)) || (0==strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_pstr_eq(X, Y) _ck_assert_str(X, ==, Y, 1, 0) + +/** + * Check two strings to determine if 0!=strcmp(X,Y) or one of them is undefined + * + * If either X or Y is NULL the test passes, however if both are NULL + * the test fails. + * If not (X!=NULL)&&(Y!=NULL)&&(0!=strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_pstr_ne(X, Y) _ck_assert_str(X, !=, Y, 0, 1) + +/* Memory location comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP memcmp(X,Y,L)' comparison */ +/* The x and y parameter swap in memcmp() is needed to handle >, >=, <, <= operators */ +/* Output is limited to CK_MAX_ASSERT_MEM_PRINT_SIZE bytes */ +#ifndef CK_MAX_ASSERT_MEM_PRINT_SIZE +#define CK_MAX_ASSERT_MEM_PRINT_SIZE 64 +#endif + /* Memory location comparison macros with improved output compared to ck_assert() */ /* OP might be any operator that can be used in '0 OP memcmp(X,Y,L)' comparison */ /* The x and y parameter swap in memcmp() is needed to handle >, >=, <, <= operators */ diff --git a/tests/check_check_master.c b/tests/check_check_master.c index 3373a4b5..5ac5f8ce 100644 --- a/tests/check_check_master.c +++ b/tests/check_check_master.c @@ -224,6 +224,10 @@ static master_test_t master_tests[] = { { "Simple Tests", "test_ck_assert_str_ge", CK_FAILURE, "Assertion 's >= t' failed: s == \"test1\", t == \"test2\"" }, { "Simple Tests", "test_ck_assert_str_ge_with_null", CK_FAILURE, "Assertion 's >= t' failed: s == (null), t == (null)" }, { "Simple Tests", "test_ck_assert_str_expr", CK_PASS, "Passed" }, + { "Simple Tests", "test_ck_assert_pstr_eq", CK_FAILURE, "Assertion '\"test1\" == s' failed: \"test1\" == \"test1\", s == \"test\"" }, + { "Simple Tests", "test_ck_assert_pstr_eq_with_null", CK_FAILURE, "Assertion 't == s' failed: t == \"test\", s == (null)" }, + { "Simple Tests", "test_ck_assert_pstr_ne", CK_FAILURE, "Assertion 't != s' failed: t == \"test2\", s == \"test2\"" }, + { "Simple Tests", "test_ck_assert_pstr_ne_with_null", CK_FAILURE, "Assertion 't != s' failed: t == (null), s == (null)" }, { "Simple Tests", "test_ck_assert_ptr_eq", CK_FAILURE, "Assertion 'x == y' failed: x == 0x1, y == 0x2" }, { "Simple Tests", "test_ck_assert_ptr_ne", CK_FAILURE, "Assertion 'x != z' failed: x == 0x1, z == 0x1" }, { "Simple Tests", "test_ck_assert_mem_eq", CK_FAILURE, "Assertion '\"\\x00\\x00\\x00\\x00\\x01\" == s' failed: \"\\x00\\x00\\x00\\x00\\x01\" == \"0000000001\", s == \"0000000002\"" }, diff --git a/tests/check_check_sub.c b/tests/check_check_sub.c index 6c81bd7b..77de05a7 100644 --- a/tests/check_check_sub.c +++ b/tests/check_check_sub.c @@ -2057,6 +2057,54 @@ START_TEST(test_ck_assert_str_expr) } END_TEST +START_TEST(test_ck_assert_pstr_eq) +{ + record_test_name(tcase_name()); + + const char *s = "test"; + ck_assert_pstr_eq("test", s); + ck_assert_pstr_eq(NULL, NULL); + record_failure_line_num(__LINE__); + ck_assert_pstr_eq("test1", s); +} +END_TEST + +START_TEST(test_ck_assert_pstr_eq_with_null) +{ + record_test_name(tcase_name()); + + const char *t = "test"; + const char *s = NULL; + record_failure_line_num(__LINE__); + ck_assert_pstr_eq(t, s); +} +END_TEST + +START_TEST(test_ck_assert_pstr_ne) +{ + record_test_name(tcase_name()); + + const char *t = "test1"; + const char *s = "test2"; + ck_assert_pstr_ne(t, s); + ck_assert_pstr_ne(t, NULL); + t = "test2"; + record_failure_line_num(__LINE__); + ck_assert_pstr_ne(t, s); +} +END_TEST + +START_TEST(test_ck_assert_pstr_ne_with_null) +{ + record_test_name(tcase_name()); + + const char *s = NULL; + const char *t = NULL; + record_failure_line_num(__LINE__); + ck_assert_pstr_ne(t, s); +} +END_TEST + START_TEST(test_ck_assert_ptr_eq) { int * x = (int*)0x1; @@ -2863,6 +2911,10 @@ Suite *make_sub_suite(void) tcase_add_test (tc_simple, test_ck_assert_str_ge); tcase_add_test (tc_simple, test_ck_assert_str_ge_with_null); tcase_add_test (tc_simple, test_ck_assert_str_expr); + tcase_add_test (tc_simple, test_ck_assert_pstr_eq); + tcase_add_test (tc_simple, test_ck_assert_pstr_eq_with_null); + tcase_add_test (tc_simple, test_ck_assert_pstr_ne); + tcase_add_test (tc_simple, test_ck_assert_pstr_ne_with_null); tcase_add_test (tc_simple, test_ck_assert_ptr_eq); tcase_add_test (tc_simple, test_ck_assert_ptr_ne); tcase_add_test (tc_simple, test_ck_assert_mem_eq);