refs: Deploy EINVALIDSPEC usage

This commit is contained in:
nulltoken 2012-11-12 15:42:15 +01:00
parent 47261d9c8a
commit 80d9d1df14
7 changed files with 114 additions and 36 deletions

View File

@ -26,13 +26,13 @@ GIT_BEGIN_DECL
* *
* The returned reference must be freed by the user. * The returned reference must be freed by the user.
* *
* See `git_reference_create_symbolic()` for documentation about valid * The name will be checked for validity.
* reference names. * See `git_reference_create_symbolic()` for rules about valid names.
* *
* @param out pointer to the looked-up reference * @param out pointer to the looked-up reference
* @param repo the repository to look up the reference * @param repo the repository to look up the reference
* @param name the long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...) * @param name the long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...)
* @return 0 or an error code (ENOTFOUND, EINVALIDSPEC) * @return 0 on success, ENOTFOUND, EINVALIDSPEC or an error code.
*/ */
GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, const char *name); GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, const char *name);
@ -43,11 +43,13 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo,
* through to the object id that it refers to. This avoids having to * through to the object id that it refers to. This avoids having to
* allocate or free any `git_reference` objects for simple situations. * allocate or free any `git_reference` objects for simple situations.
* *
* The name will be checked for validity.
* See `git_reference_create_symbolic()` for rules about valid names.
*
* @param out Pointer to oid to be filled in * @param out Pointer to oid to be filled in
* @param repo The repository in which to look up the reference * @param repo The repository in which to look up the reference
* @param name The long name for the reference * @param name The long name for the reference
* @return 0 on success, -1 if name could not be resolved (EINVALIDSPEC, * @return 0 on success, ENOTFOUND, EINVALIDSPEC or an error code.
* ENOTFOUND, etc)
*/ */
GIT_EXTERN(int) git_reference_name_to_id( GIT_EXTERN(int) git_reference_name_to_id(
git_oid *out, git_repository *repo, const char *name); git_oid *out, git_repository *repo, const char *name);
@ -79,7 +81,7 @@ GIT_EXTERN(int) git_reference_name_to_id(
* @param name The name of the reference * @param name The name of the reference
* @param target The target of the reference * @param target The target of the reference
* @param force Overwrite existing references * @param force Overwrite existing references
* @return 0 or an error code (EEXISTS, EINVALIDSPEC) * @return 0 on success, EEXISTS, EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force); GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force);
@ -111,7 +113,7 @@ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repositor
* @param name The name of the reference * @param name The name of the reference
* @param id The object id pointed to by the reference. * @param id The object id pointed to by the reference.
* @param force Overwrite existing references * @param force Overwrite existing references
* @return 0 or an error code (EINVALIDSPEC, EEXISTS) * @return 0 on success, EEXISTS, EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force); GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force);
@ -193,9 +195,12 @@ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref);
* *
* The reference will be automatically updated in memory and on disk. * The reference will be automatically updated in memory and on disk.
* *
* The target name will be checked for validity.
* See `git_reference_create_symbolic()` for rules about valid names.
*
* @param ref The reference * @param ref The reference
* @param target The new target for the reference * @param target The new target for the reference
* @return 0 or an error code (EINVALIDSPEC) * @return 0 on success, EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reference_symbolic_set_target(git_reference *ref, const char *target); GIT_EXTERN(int) git_reference_symbolic_set_target(git_reference *ref, const char *target);
@ -216,8 +221,9 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const git_oid *id);
* Rename an existing reference. * Rename an existing reference.
* *
* This method works for both direct and symbolic references. * This method works for both direct and symbolic references.
* The new name will be checked for validity and may be *
* modified into a normalized form. * The new name will be checked for validity.
* See `git_reference_create_symbolic()` for rules about valid names.
* *
* The given git_reference will be updated in place. * The given git_reference will be updated in place.
* *
@ -234,7 +240,7 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const git_oid *id);
* @param ref The reference to rename * @param ref The reference to rename
* @param name The new name for the reference * @param name The new name for the reference
* @param force Overwrite an existing reference * @param force Overwrite an existing reference
* @return 0 or an error code (EINVALIDSPEC, EEXISTS) * @return 0 on success, EINVALIDSPEC, EEXISTS or an error code
* *
*/ */
GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *name, int force); GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *name, int force);
@ -446,13 +452,15 @@ typedef enum {
* Once normalized, if the reference name is valid, it will be returned in * Once normalized, if the reference name is valid, it will be returned in
* the user allocated buffer. * the user allocated buffer.
* *
* See `git_reference_create_symbolic()` for rules about valid names.
*
* @param buffer_out User allocated buffer to store normalized name * @param buffer_out User allocated buffer to store normalized name
* @param buffer_size Size of buffer_out * @param buffer_size Size of buffer_out
* @param name Reference name to be checked. * @param name Reference name to be checked.
* @param flags Flags to constrain name validation rules - see the * @param flags Flags to constrain name validation rules - see the
* GIT_REF_FORMAT constants above. * GIT_REF_FORMAT constants above.
* @return 0 on success or error code (GIT_EBUFS if buffer is too small, -1 * @return 0 on success, GIT_EBUFS if buffer is too small, EINVALIDSPEC
* if reference is invalid) * or an error code.
*/ */
GIT_EXTERN(int) git_reference_normalize_name( GIT_EXTERN(int) git_reference_normalize_name(
char *buffer_out, char *buffer_out,

View File

@ -1215,11 +1215,11 @@ int git_reference_symbolic_create(
git_reference *ref = NULL; git_reference *ref = NULL;
int error; int error;
if (git_reference__normalize_name_lax( if ((error = git_reference__normalize_name_lax(
normalized, normalized,
sizeof(normalized), sizeof(normalized),
name) < 0) name)) < 0)
return -1; return error;
if ((error = reference_can_write(repo, normalized, NULL, force)) < 0) if ((error = reference_can_write(repo, normalized, NULL, force)) < 0)
return error; return error;
@ -1255,11 +1255,11 @@ int git_reference_create(
git_reference *ref = NULL; git_reference *ref = NULL;
char normalized[GIT_REFNAME_MAX]; char normalized[GIT_REFNAME_MAX];
if (git_reference__normalize_name_lax( if ((error = git_reference__normalize_name_lax(
normalized, normalized,
sizeof(normalized), sizeof(normalized),
name) < 0) name)) < 0)
return -1; return error;
if ((error = reference_can_write(repo, normalized, NULL, force)) < 0) if ((error = reference_can_write(repo, normalized, NULL, force)) < 0)
return error; return error;
@ -1330,6 +1330,7 @@ int git_reference_set_target(git_reference *ref, const git_oid *id)
*/ */
int git_reference_symbolic_set_target(git_reference *ref, const char *target) int git_reference_symbolic_set_target(git_reference *ref, const char *target)
{ {
int error;
char normalized[GIT_REFNAME_MAX]; char normalized[GIT_REFNAME_MAX];
if ((ref->flags & GIT_REF_SYMBOLIC) == 0) { if ((ref->flags & GIT_REF_SYMBOLIC) == 0) {
@ -1338,11 +1339,11 @@ int git_reference_symbolic_set_target(git_reference *ref, const char *target)
return -1; return -1;
} }
if (git_reference__normalize_name_lax( if ((error = git_reference__normalize_name_lax(
normalized, normalized,
sizeof(normalized), sizeof(normalized),
target)) target)) < 0)
return -1; return error;
git__free(ref->target.symbolic); git__free(ref->target.symbolic);
ref->target.symbolic = git__strdup(normalized); ref->target.symbolic = git__strdup(normalized);
@ -1363,12 +1364,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
GIT_REF_FORMAT_ALLOW_ONELEVEL GIT_REF_FORMAT_ALLOW_ONELEVEL
: GIT_REF_FORMAT_NORMAL; : GIT_REF_FORMAT_NORMAL;
if (git_reference_normalize_name( if ((result = git_reference_normalize_name(
normalized, normalized,
sizeof(normalized), sizeof(normalized),
new_name, new_name,
normalization_flags) < 0) normalization_flags)) < 0)
return -1; return result;
if ((result = reference_can_write(ref->owner, normalized, ref->name, force)) < 0) if ((result = reference_can_write(ref->owner, normalized, ref->name, force)) < 0)
return result; return result;
@ -1645,7 +1646,7 @@ int git_reference__normalize_name(
// Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 // Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100
char *current; char *current;
int segment_len, segments_count = 0, error = -1; int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
unsigned int process_flags; unsigned int process_flags;
bool normalize = (buf != NULL); bool normalize = (buf != NULL);
assert(name); assert(name);
@ -1677,8 +1678,10 @@ int git_reference__normalize_name(
git_buf_truncate(buf, git_buf_truncate(buf,
cur_len + segment_len + (segments_count ? 1 : 0)); cur_len + segment_len + (segments_count ? 1 : 0));
if (git_buf_oom(buf)) if (git_buf_oom(buf)) {
error = -1;
goto cleanup; goto cleanup;
}
} }
segments_count++; segments_count++;
@ -1721,7 +1724,7 @@ int git_reference__normalize_name(
error = 0; error = 0;
cleanup: cleanup:
if (error) if (error == GIT_EINVALIDSPEC)
giterr_set( giterr_set(
GITERR_REFERENCE, GITERR_REFERENCE,
"The given reference name '%s' is not valid", name); "The given reference name '%s' is not valid", name);

View File

@ -149,3 +149,19 @@ void test_refs_create__propagate_eexists(void)
error = git_reference_symbolic_create(&ref, g_repo, "HEAD", current_head_target, false); error = git_reference_symbolic_create(&ref, g_repo, "HEAD", current_head_target, false);
cl_assert(error == GIT_EEXISTS); cl_assert(error == GIT_EEXISTS);
} }
void test_refs_create__creating_a_reference_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
git_reference *new_reference;
git_oid id;
const char *name = "refs/heads/inv@{id";
git_oid_fromstr(&id, current_master_tip);
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_create(
&new_reference, g_repo, name, &id, 0));
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(
&new_reference, g_repo, name, current_head_target, 0));
}

View File

@ -21,7 +21,9 @@ static void ensure_refname_invalid(unsigned int flags, const char *input_refname
{ {
char buffer_out[GIT_REFNAME_MAX]; char buffer_out[GIT_REFNAME_MAX];
cl_git_fail(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags)); cl_assert_equal_i(
GIT_EINVALIDSPEC,
git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
} }
void test_refs_normalize__can_normalize_a_direct_reference_name(void) void test_refs_normalize__can_normalize_a_direct_reference_name(void)

View File

@ -224,10 +224,14 @@ void test_refs_read__unfound_return_ENOTFOUND(void)
{ {
git_reference *reference; git_reference *reference;
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "TEST_MASTER")); cl_assert_equal_i(GIT_ENOTFOUND,
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/test/master")); git_reference_lookup(&reference, g_repo, "TEST_MASTER"));
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/master")); cl_assert_equal_i(GIT_ENOTFOUND,
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master")); git_reference_lookup(&reference, g_repo, "refs/test/master"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_lookup(&reference, g_repo, "refs/tags/test/master"));
cl_assert_equal_i(GIT_ENOTFOUND,
git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master"));
} }
static void assert_is_branch(const char *name, bool expected_branchness) static void assert_is_branch(const char *name, bool expected_branchness)
@ -245,3 +249,15 @@ void test_refs_read__can_determine_if_a_reference_is_a_local_branch(void)
assert_is_branch("refs/remotes/test/master", false); assert_is_branch("refs/remotes/test/master", false);
assert_is_branch("refs/tags/e90810b", false); assert_is_branch("refs/tags/e90810b", false);
} }
void test_refs_read__invalid_name_returns_EINVALIDSPEC(void)
{
git_reference *reference;
git_oid id;
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reference_lookup(&reference, g_repo, "refs/heads/Inv@{id"));
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reference_name_to_id(&id, g_repo, "refs/heads/Inv@{id"));
}

View File

@ -180,10 +180,14 @@ void test_refs_rename__invalid_name(void)
cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name)); cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
/* Can not be renamed with an invalid name. */ /* Can not be renamed with an invalid name. */
cl_git_fail(git_reference_rename(looked_up_ref, "Hello! I'm a very invalid name.", 0)); cl_assert_equal_i(
GIT_EINVALIDSPEC,
git_reference_rename(looked_up_ref, "Hello! I'm a very invalid name.", 0));
/* Can not be renamed outside of the refs hierarchy. */ /* Can not be renamed outside of the refs hierarchy
cl_git_fail(git_reference_rename(looked_up_ref, "i-will-sudo-you", 0)); * unless it's ALL_CAPS_AND_UNDERSCORES.
*/
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_rename(looked_up_ref, "i-will-sudo-you", 0));
/* Failure to rename it hasn't corrupted its state */ /* Failure to rename it hasn't corrupted its state */
git_reference_free(looked_up_ref); git_reference_free(looked_up_ref);

29
tests-clar/refs/update.c Normal file
View File

@ -0,0 +1,29 @@
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *g_repo;
void test_refs_update__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_update__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refs_update__updating_the_target_of_a_symref_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
git_reference *head;
cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE));
cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head));
cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_set_target(
head, "refs/heads/inv@{id"));
git_reference_free(head);
}