diff options
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | include/git2/errors.h | 3 | ||||
-rw-r--r-- | src/assert_safe.h | 58 | ||||
-rw-r--r-- | src/common.h | 1 | ||||
-rw-r--r-- | tests/core/assert.c | 94 |
5 files changed, 170 insertions, 1 deletions
@@ -47,6 +47,7 @@ Table of Contents * [Compiler and linker options](#compiler-and-linker-options) * [MacOS X](#macos-x) * [Android](#android) + * [MinGW](#mingw) * [Language Bindings](#language-bindings) * [How Can I Contribute?](#how-can-i-contribute) * [License](#license) @@ -304,6 +305,20 @@ with full path to the toolchain): Add `-DCMAKE_TOOLCHAIN_FILE={pathToToolchainFile}` to cmake command when configuring. +MinGW +----- + +If you want to build the library in MinGW environment with SSH support enabled, +you may need to pass `-DCMAKE_LIBRARY_PATH="${MINGW_PREFIX}/${MINGW_CHOST}/lib/"` flag +to CMake when configuring. This is because CMake cannot find the Win32 libraries in +MinGW folders by default and you might see an error message stating that CMake +could not resolve `ws2_32` library during configuration. + +Another option would be to install `msys2-w32api-runtime` package before configuring. +This package installs the Win32 libraries into `/usr/lib` folder which is by default +recognized as the library path by CMake. Please note though that this package is meant +for MSYS subsystem which is different from MinGW. + Language Bindings ================================== diff --git a/include/git2/errors.h b/include/git2/errors.h index 5c85c4d6c..8887b3299 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -107,7 +107,8 @@ typedef enum { GIT_ERROR_PATCH, GIT_ERROR_WORKTREE, GIT_ERROR_SHA1, - GIT_ERROR_HTTP + GIT_ERROR_HTTP, + GIT_ERROR_INTERNAL } git_error_t; /** diff --git a/src/assert_safe.h b/src/assert_safe.h new file mode 100644 index 000000000..8c261100f --- /dev/null +++ b/src/assert_safe.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_assert_safe_h__ +#define INCLUDE_assert_safe_h__ + +/* + * In a debug build, we'll assert(3) for aide in debugging. In release + * builds, we will provide macros that will set an error message that + * indicate a failure and return. Note that memory leaks can occur in + * a release-mode assertion failure -- it is impractical to provide + * safe clean up routines in these very extreme failures, but care + * should be taken to not leak very large objects. + */ + +#if (defined(_DEBUG) || defined(GIT_ASSERT_HARD)) && GIT_ASSERT_HARD != 0 +# include <assert.h> + +# define GIT_ASSERT(expr) assert(expr) +# define GIT_ASSERT_ARG(expr) assert(expr) + +# define GIT_ASSERT_WITH_RETVAL(expr, fail) assert(expr) +# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) assert(expr) +#else + +/** Internal consistency check to stop the function. */ +# define GIT_ASSERT(expr) GIT_ASSERT_WITH_RETVAL(expr, -1) + +/** + * Assert that a consumer-provided argument is valid, setting an + * actionable error message and returning -1 if it is not. + */ +# define GIT_ASSERT_ARG(expr) GIT_ASSERT_ARG_WITH_RETVAL(expr, -1) + +/** Internal consistency check to return the `fail` param on failure. */ +# define GIT_ASSERT_WITH_RETVAL(expr, fail) \ + GIT_ASSERT__WITH_RETVAL(expr, GIT_ERROR_INTERNAL, "unrecoverable internal error", fail) + +/** + * Assert that a consumer-provided argument is valid, setting an + * actionable error message and returning the `fail` param if not. + */ +# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) \ + GIT_ASSERT__WITH_RETVAL(expr, GIT_ERROR_INVALID, "invalid argument", fail) + +# define GIT_ASSERT__WITH_RETVAL(expr, code, msg, fail) do { \ + if (!(expr)) { \ + git_error_set(code, "%s: '%s'", msg, #expr); \ + return fail; \ + } \ + } while(0) + +#endif /* GIT_ASSERT_HARD */ + +#endif diff --git a/src/common.h b/src/common.h index a4152caf2..2b1a4a456 100644 --- a/src/common.h +++ b/src/common.h @@ -80,6 +80,7 @@ #include "errors.h" #include "thread-utils.h" #include "integer.h" +#include "assert_safe.h" /* * Include the declarations for deprecated functions; this ensures diff --git a/tests/core/assert.c b/tests/core/assert.c new file mode 100644 index 000000000..ef75624b9 --- /dev/null +++ b/tests/core/assert.c @@ -0,0 +1,94 @@ +#ifdef GIT_ASSERT_HARD +# undef GIT_ASSERT_HARD +#endif + +#define GIT_ASSERT_HARD 0 + +#include "clar_libgit2.h" + +static const char *hello_world = "hello, world"; +static const char *fail = "FAIL"; + +static int dummy_fn(const char *myarg) +{ + GIT_ASSERT_ARG(myarg); + GIT_ASSERT_ARG(myarg != hello_world); + return 0; +} + +static const char *fn_returns_string(const char *myarg) +{ + GIT_ASSERT_ARG_WITH_RETVAL(myarg, fail); + GIT_ASSERT_ARG_WITH_RETVAL(myarg != hello_world, fail); + + return myarg; +} + +static int bad_math(void) +{ + GIT_ASSERT(1 + 1 == 3); + return 42; +} + +static const char *bad_returns_string(void) +{ + GIT_ASSERT_WITH_RETVAL(1 + 1 == 3, NULL); + return hello_world; +} + +void test_core_assert__argument(void) +{ + cl_git_fail(dummy_fn(NULL)); + cl_assert(git_error_last()); + cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass); + cl_assert_equal_s("invalid argument: 'myarg'", git_error_last()->message); + + cl_git_fail(dummy_fn(hello_world)); + cl_assert(git_error_last()); + cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass); + cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message); + + cl_git_pass(dummy_fn("foo")); +} + +void test_core_assert__argument_with_non_int_return_type(void) +{ + const char *foo = "foo"; + + cl_assert_equal_p(fail, fn_returns_string(NULL)); + cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass); + cl_assert_equal_s("invalid argument: 'myarg'", git_error_last()->message); + + cl_assert_equal_p(fail, fn_returns_string(hello_world)); + cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass); + cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message); + + cl_assert_equal_p(foo, fn_returns_string(foo)); +} + +void test_core_assert__argument_with_void_return_type(void) +{ + const char *foo = "foo"; + + git_error_clear(); + fn_returns_string(hello_world); + cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass); + cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message); + + git_error_clear(); + cl_assert_equal_p(foo, fn_returns_string(foo)); + cl_assert_equal_p(NULL, git_error_last()); +} + +void test_core_assert__internal(void) +{ + cl_git_fail(bad_math()); + cl_assert(git_error_last()); + cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass); + cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message); + + cl_assert_equal_p(NULL, bad_returns_string()); + cl_assert(git_error_last()); + cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass); + cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message); +} |