Skip to content

Commit cbae1c2

Browse files
committed
assert: allow non-int returning functions to assert
Include GIT_ASSERT_WITH_RETVAL and GIT_ASSERT_ARG_WITH_RETVAL so that functions that do not return int (or more precisely, where `-1` would not be an error code) can assert. This allows functions that return, eg, NULL on an error code to do that by passing the return value (in this example, `NULL`) as a second parameter to the GIT_ASSERT_WITH_RETVAL functions.
1 parent a95096b commit cbae1c2

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

src/assert_safe.h

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,35 @@
2121

2222
# define GIT_ASSERT(expr) assert(expr)
2323
# define GIT_ASSERT_ARG(expr) assert(expr)
24+
25+
# define GIT_ASSERT_WITH_RETVAL(expr, fail) assert(expr)
26+
# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) assert(expr)
2427
#else
2528

29+
/** Internal consistency check to stop the function. */
30+
# define GIT_ASSERT(expr) GIT_ASSERT_WITH_RETVAL(expr, -1)
31+
2632
/**
2733
* Assert that a consumer-provided argument is valid, setting an
2834
* actionable error message and returning -1 if it is not.
2935
*/
30-
# define GIT_ASSERT_ARG(expr) do { \
31-
if (!(expr)) { \
32-
git_error_set(GIT_ERROR_INVALID, \
33-
"invalid argument: '%s'", \
34-
#expr); \
35-
return -1; \
36-
} \
37-
} while(0)
36+
# define GIT_ASSERT_ARG(expr) GIT_ASSERT_ARG_WITH_RETVAL(expr, -1)
37+
38+
/** Internal consistency check to return the `fail` param on failure. */
39+
# define GIT_ASSERT_WITH_RETVAL(expr, fail) \
40+
GIT_ASSERT__WITH_RETVAL(expr, GIT_ERROR_INTERNAL, "unrecoverable internal error", fail)
41+
42+
/**
43+
* Assert that a consumer-provided argument is valid, setting an
44+
* actionable error message and returning the `fail` param if not.
45+
*/
46+
# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) \
47+
GIT_ASSERT__WITH_RETVAL(expr, GIT_ERROR_INVALID, "invalid argument", fail)
3848

39-
/* Internal consistency check to stop the function. */
40-
# define GIT_ASSERT(expr) do { \
49+
# define GIT_ASSERT__WITH_RETVAL(expr, code, msg, fail) do { \
4150
if (!(expr)) { \
42-
git_error_set(GIT_ERROR_INTERNAL, \
43-
"unrecoverable internal error: '%s'", \
44-
#expr); \
45-
return -1; \
51+
git_error_set(code, "%s: '%s'", msg, #expr); \
52+
return fail; \
4653
} \
4754
} while(0)
4855

tests/core/assert.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
#ifdef GIT_ASSERT_HARD
2+
# undef GIT_ASSERT_HARD
3+
#endif
4+
15
#define GIT_ASSERT_HARD 0
26

37
#include "clar_libgit2.h"
48

59
static const char *hello_world = "hello, world";
10+
static const char *fail = "FAIL";
611

712
static int dummy_fn(const char *myarg)
813
{
@@ -11,12 +16,26 @@ static int dummy_fn(const char *myarg)
1116
return 0;
1217
}
1318

19+
static const char *fn_returns_string(const char *myarg)
20+
{
21+
GIT_ASSERT_ARG_WITH_RETVAL(myarg, fail);
22+
GIT_ASSERT_ARG_WITH_RETVAL(myarg != hello_world, fail);
23+
24+
return myarg;
25+
}
26+
1427
static int bad_math(void)
1528
{
1629
GIT_ASSERT(1 + 1 == 3);
1730
return 42;
1831
}
1932

33+
static const char *bad_returns_string(void)
34+
{
35+
GIT_ASSERT_WITH_RETVAL(1 + 1 == 3, NULL);
36+
return hello_world;
37+
}
38+
2039
void test_core_assert__argument(void)
2140
{
2241
cl_git_fail(dummy_fn(NULL));
@@ -32,10 +51,44 @@ void test_core_assert__argument(void)
3251
cl_git_pass(dummy_fn("foo"));
3352
}
3453

54+
void test_core_assert__argument_with_non_int_return_type(void)
55+
{
56+
const char *foo = "foo";
57+
58+
cl_assert_equal_p(fail, fn_returns_string(NULL));
59+
cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
60+
cl_assert_equal_s("invalid argument: 'myarg'", git_error_last()->message);
61+
62+
cl_assert_equal_p(fail, fn_returns_string(hello_world));
63+
cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
64+
cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message);
65+
66+
cl_assert_equal_p(foo, fn_returns_string(foo));
67+
}
68+
69+
void test_core_assert__argument_with_void_return_type(void)
70+
{
71+
const char *foo = "foo";
72+
73+
git_error_clear();
74+
fn_returns_string(hello_world);
75+
cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
76+
cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message);
77+
78+
git_error_clear();
79+
cl_assert_equal_p(foo, fn_returns_string(foo));
80+
cl_assert_equal_p(NULL, git_error_last());
81+
}
82+
3583
void test_core_assert__internal(void)
3684
{
3785
cl_git_fail(bad_math());
3886
cl_assert(git_error_last());
3987
cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass);
4088
cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message);
89+
90+
cl_assert_equal_p(NULL, bad_returns_string());
91+
cl_assert(git_error_last());
92+
cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass);
93+
cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message);
4194
}

0 commit comments

Comments
 (0)