]> git.proxmox.com Git - libgit2.git/commitdiff
refs: expose git_reference_normalize_name()
authornulltoken <emeric.fermas@gmail.com>
Sun, 26 Aug 2012 20:08:22 +0000 (22:08 +0200)
committernulltoken <emeric.fermas@gmail.com>
Mon, 27 Aug 2012 06:41:26 +0000 (08:41 +0200)
include/git2/refs.h
src/refs.c
tests-clar/refs/normalize.c

index 9e70600755e4b9d98c5a8cd1ec569a4edfabeb9d..6a8513b3d7680faf8da74a25c223e02f79dd5cee 100644 (file)
@@ -376,6 +376,54 @@ GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
  */
 GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
 
+enum {
+       GIT_REF_FORMAT_NORMAL = 0,
+
+       /**
+        * Control whether one-level refnames are accepted
+        * (i.e., refnames that do not contain multiple /-separated
+        * components)
+        */
+       GIT_REF_FORMAT_ALLOW_ONELEVEL = (1 << 0),
+
+       /**
+        * Interpret the provided name as a reference pattern for a
+        * refspec (as used with remote repositories). If this option
+        * is enabled, the name is allowed to contain a single * (<star>)
+        * in place of a one full pathname component
+        * (e.g., foo/<star>/bar but not foo/bar<star>).
+        */
+       GIT_REF_FORMAT_REFSPEC_PATTERN = (1 << 1),
+};
+
+/**
+ * Normalize the reference name by removing any leading
+ * slash (/) characters and collapsing runs of adjacent slashes
+ * between name components into a single slash.
+ *
+ * Once normalized, if the reference name is valid, it will be
+ * returned in the user allocated buffer.
+ *
+ * TODO: Implement handling of GIT_REF_FORMAT_REFSPEC_PATTERN
+ *
+ * @param buffer_out The user allocated buffer where the
+ * normalized name will be stored.
+ *
+ * @param buffer_size buffer_out size
+ *
+ * @param name name to be checked.
+ *
+ * @param flags Flags to determine the options to be applied while
+ * checking the validatity of the name.
+ *
+ * @return 0 or an error code.
+ */
+GIT_EXTERN(int) git_reference_normalize_name(
+       char *buffer_out,
+       size_t buffer_size,
+       const char *name,
+       unsigned int flags);
+
 /** @} */
 GIT_END_DECL
 #endif
index cf55a6fd5796dad65328ab9701c7e077a384cea9..9fc194cb6a1abe9b712f893d8ad5322cef2d11d8 100644 (file)
@@ -68,11 +68,6 @@ static int reference_path_available(git_repository *repo,
 static int reference_delete(git_reference *ref);
 static int reference_lookup(git_reference *ref);
 
-/* name normalization */
-static int normalize_name(char *buffer_out, size_t out_size,
-       const char *name, int is_oid_ref);
-
-
 void git_reference_free(git_reference *reference)
 {
        if (reference == NULL)
@@ -1099,9 +1094,12 @@ int git_reference_lookup_resolved(
        scan->name = git__calloc(GIT_REFNAME_MAX + 1, sizeof(char));
        GITERR_CHECK_ALLOC(scan->name);
 
-       if ((result = normalize_name(scan->name, GIT_REFNAME_MAX, name, 0)) < 0) {
-               git_reference_free(scan);
-               return result;
+       if ((result = git_reference__normalize_name(
+               scan->name,
+               GIT_REFNAME_MAX,
+               name)) < 0) {
+                       git_reference_free(scan);
+                       return result;
        }
 
        scan->target.symbolic = git__strdup(scan->name);
@@ -1198,8 +1196,11 @@ int git_reference_create_symbolic(
        char normalized[GIT_REFNAME_MAX];
        git_reference *ref = NULL;
 
-       if (normalize_name(normalized, sizeof(normalized), name, 0) < 0)
-               return -1;
+       if (git_reference__normalize_name(
+               normalized,
+               sizeof(normalized),
+               name) < 0)
+                       return -1;
 
        if (reference_can_write(repo, normalized, NULL, force) < 0)
                return -1;
@@ -1234,8 +1235,11 @@ int git_reference_create_oid(
        git_reference *ref = NULL;
        char normalized[GIT_REFNAME_MAX];
 
-       if (normalize_name(normalized, sizeof(normalized), name, 1) < 0)
-               return -1;
+       if (git_reference__normalize_name_oid(
+               normalized,
+               sizeof(normalized),
+               name) < 0)
+                       return -1;
 
        if (reference_can_write(repo, normalized, NULL, force) < 0)
                return -1;
@@ -1314,8 +1318,11 @@ int git_reference_set_target(git_reference *ref, const char *target)
                return -1;
        }
 
-       if (normalize_name(normalized, sizeof(normalized), target, 0))
-               return -1;
+       if (git_reference__normalize_name(
+               normalized,
+               sizeof(normalized),
+               target))
+                       return -1;
 
        git__free(ref->target.symbolic);
        ref->target.symbolic = git__strdup(normalized);
@@ -1327,15 +1334,23 @@ int git_reference_set_target(git_reference *ref, const char *target)
 int git_reference_rename(git_reference *ref, const char *new_name, int force)
 {
        int result;
+       unsigned int normalization_flags;
        git_buf aux_path = GIT_BUF_INIT;
        char normalized[GIT_REFNAME_MAX];
 
        const char *head_target = NULL;
        git_reference *head = NULL;
 
-       if (normalize_name(normalized, sizeof(normalized),
-               new_name, ref->flags & GIT_REF_OID) < 0)
-               return -1;
+       normalization_flags = ref->flags & GIT_REF_SYMBOLIC ?
+               GIT_REF_FORMAT_ALLOW_ONELEVEL
+               : GIT_REF_FORMAT_NORMAL;
+
+       if (git_reference_normalize_name(
+               normalized,
+               sizeof(normalized),
+               new_name,
+               normalization_flags) < 0)
+                       return -1;
 
        if (reference_can_write(ref->owner, normalized, ref->name, force) < 0)
                return -1;
@@ -1565,11 +1580,11 @@ static int is_valid_ref_char(char ch)
        }
 }
 
-static int normalize_name(
+int git_reference_normalize_name(
        char *buffer_out,
-       size_t out_size,
+       size_t buffer_size,
        const char *name,
-       int is_oid_ref)
+       unsigned int flags)
 {
        const char *name_end, *buffer_out_start;
        const char *current;
@@ -1577,12 +1592,17 @@ static int normalize_name(
 
        assert(name && buffer_out);
 
+       if (flags & GIT_REF_FORMAT_REFSPEC_PATTERN) {
+               giterr_set(GITERR_INVALID, "Unimplemented");
+               return -1;
+       }
+
        buffer_out_start = buffer_out;
        current = name;
        name_end = name + strlen(name);
 
        /* Terminating null byte */
-       out_size--;
+       buffer_size--;
 
        /* A refname can not be empty */
        if (name_end == name)
@@ -1592,7 +1612,7 @@ static int normalize_name(
        if (*(name_end - 1) == '.' || *(name_end - 1) == '/')
                goto invalid_name;
 
-       while (current < name_end && out_size) {
+       while (current < name_end && buffer_size > 0) {
                if (!is_valid_ref_char(*current))
                        goto invalid_name;
 
@@ -1615,19 +1635,29 @@ static int normalize_name(
                }
 
                if (*current == '/')
-                       contains_a_slash = 1;
+                       if (buffer_out > buffer_out_start)
+                               contains_a_slash = 1;
+                       else {
+                               current++;
+                               continue;
+                       }
+
 
                *buffer_out++ = *current++;
-               out_size--;
+               buffer_size--;
        }
 
-       if (!out_size)
-               goto invalid_name;
+       if (current < name_end) {
+               giterr_set(
+               GITERR_REFERENCE,
+               "The provided buffer is too short to hold the normalization of '%s'", name);
+               return GIT_EBUFS;
+       }
 
        /* Object id refname have to contain at least one slash, except
         * for HEAD in a detached state or MERGE_HEAD if we're in the
         * middle of a merge */
-       if (is_oid_ref &&
+       if (!(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL) &&
                !contains_a_slash &&
                strcmp(name, GIT_HEAD_FILE) != 0 &&
                strcmp(name, GIT_MERGE_HEAD_FILE) != 0 &&
@@ -1640,18 +1670,12 @@ static int normalize_name(
 
        *buffer_out = '\0';
 
-       /*
-        * For object id references, name has to start with refs/. Again,
-        * we need to allow HEAD to be in a detached state.
-        */
-       if (is_oid_ref && !(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) ||
-               strcmp(buffer_out_start, GIT_HEAD_FILE)))
-               goto invalid_name;
-
        return 0;
 
 invalid_name:
-       giterr_set(GITERR_REFERENCE, "The given reference name is not valid");
+       giterr_set(
+               GITERR_REFERENCE,
+               "The given reference name '%s' is not valid", name);
        return -1;
 }
 
@@ -1660,7 +1684,11 @@ int git_reference__normalize_name(
        size_t out_size,
        const char *name)
 {
-       return normalize_name(buffer_out, out_size, name, 0);
+       return git_reference_normalize_name(
+               buffer_out,
+               out_size,
+               name,
+               GIT_REF_FORMAT_ALLOW_ONELEVEL);
 }
 
 int git_reference__normalize_name_oid(
@@ -1668,7 +1696,11 @@ int git_reference__normalize_name_oid(
        size_t out_size,
        const char *name)
 {
-       return normalize_name(buffer_out, out_size, name, 1);
+       return git_reference_normalize_name(
+               buffer_out,
+               out_size,
+               name,
+               GIT_REF_FORMAT_NORMAL);
 }
 
 #define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
index 135d0a9b632ef57d823425c3dc81603dca09b8f2..4e80e4b0ba49bb91b3fbfa96bc3ec3f4a4aaa263 100644 (file)
 #include "git2/reflog.h"
 #include "reflog.h"
 
-
 // Helpers
-static void ensure_refname_normalized(int is_oid_ref,
+static void ensure_refname_normalized(unsigned int flags,
                                       const char *input_refname,
                                       const char *expected_refname)
 {
        char buffer_out[GIT_REFNAME_MAX];
 
-       if (is_oid_ref)
-               cl_git_pass(git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname));
-       else
-               cl_git_pass(git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname));
+       cl_git_pass(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
 
-   if (expected_refname)
-          cl_assert(0 == strcmp(buffer_out, expected_refname));
+       cl_assert_equal_i(0, strcmp(buffer_out, expected_refname));
 }
 
-static void ensure_refname_invalid(int is_oid_ref, const char *input_refname)
+static void ensure_refname_invalid(unsigned int flags, const char *input_refname)
 {
        char buffer_out[GIT_REFNAME_MAX];
 
-   if (is_oid_ref)
-      cl_git_fail(git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname));
-   else
-      cl_git_fail(git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname));
+       cl_git_fail(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
 }
 
-#define OID_REF 1
-#define SYM_REF 0
-
+void test_refs_normalize__can_normalize_a_direct_reference_name(void)
+{
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/dummy/a", "refs/dummy/a");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/stash", "refs/stash");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/tags/a", "refs/tags/a");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/a/b", "refs/heads/a/b");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/a./b", "refs/heads/a./b");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "/refs///heads///a", "refs/heads/a");
+}
 
+void test_refs_normalize__can_normalize_some_specific_one_level_direct_reference_names(void)
+{
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "HEAD", "HEAD");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "MERGE_HEAD", "MERGE_HEAD");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "FETCH_HEAD", "FETCH_HEAD");
+}
 
-void test_refs_normalize__direct(void)
+void test_refs_normalize__cannot_normalize_any_direct_reference_name(void)
 {
-   // normalize a direct (OID) reference name
-       ensure_refname_invalid(OID_REF, "a");
-       ensure_refname_invalid(OID_REF, "");
-       ensure_refname_invalid(OID_REF, "refs/heads/a/");
-       ensure_refname_invalid(OID_REF, "refs/heads/a.");
-       ensure_refname_invalid(OID_REF, "refs/heads/a.lock");
-       ensure_refname_normalized(OID_REF, "refs/dummy/a", NULL);
-       ensure_refname_normalized(OID_REF, "refs/stash", NULL);
-       ensure_refname_normalized(OID_REF, "refs/tags/a", "refs/tags/a");
-       ensure_refname_normalized(OID_REF, "refs/heads/a/b", "refs/heads/a/b");
-       ensure_refname_normalized(OID_REF, "refs/heads/a./b", "refs/heads/a./b");
-       ensure_refname_invalid(OID_REF, "refs/heads/foo?bar");
-       ensure_refname_invalid(OID_REF, "refs/heads\foo");
-       ensure_refname_normalized(OID_REF, "refs/heads/v@ation", "refs/heads/v@ation");
-       ensure_refname_normalized(OID_REF, "refs///heads///a", "refs/heads/a");
-       ensure_refname_invalid(OID_REF, "refs/heads/.a/b");
-       ensure_refname_invalid(OID_REF, "refs/heads/foo/../bar");
-       ensure_refname_invalid(OID_REF, "refs/heads/foo..bar");
-       ensure_refname_invalid(OID_REF, "refs/heads/./foo");
-       ensure_refname_invalid(OID_REF, "refs/heads/v@{ation");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "a");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "/a");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "//a");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/a/");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/a.");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/a.lock");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/foo?bar");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads\foo");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/.a/b");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/foo/../bar");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/foo..bar");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/./foo");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "refs/heads/v@{ation");
 }
 
 void test_refs_normalize__symbolic(void)
 {
-   // normalize a symbolic reference name
-       ensure_refname_normalized(SYM_REF, "a", "a");
-       ensure_refname_normalized(SYM_REF, "a/b", "a/b");
-       ensure_refname_normalized(SYM_REF, "refs///heads///a", "refs/heads/a");
-       ensure_refname_invalid(SYM_REF, "");
-       ensure_refname_invalid(SYM_REF, "heads\foo");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads\foo");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "///");
+
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "a", "a");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "a/b", "a/b");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs///heads///a", "refs/heads/a");
+
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "HEAD", "HEAD");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "MERGE_HEAD", "MERGE_HEAD");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "FETCH_HEAD", "FETCH_HEAD");
 }
 
 /* Ported from JGit, BSD licence.
@@ -77,31 +118,42 @@ void test_refs_normalize__jgit_suite(void)
    // tests borrowed from JGit
 
 /* EmptyString */
-       ensure_refname_invalid(SYM_REF, "");
-       ensure_refname_invalid(SYM_REF, "/");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "/");
 
 /* MustHaveTwoComponents */
-       ensure_refname_invalid(OID_REF, "master");
-       ensure_refname_normalized(SYM_REF, "heads/master", "heads/master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_NORMAL, "master");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads/master", "heads/master");
 
 /* ValidHead */
 
-       ensure_refname_normalized(SYM_REF, "refs/heads/master", "refs/heads/master");
-       ensure_refname_normalized(SYM_REF, "refs/heads/pu", "refs/heads/pu");
-       ensure_refname_normalized(SYM_REF, "refs/heads/z", "refs/heads/z");
-       ensure_refname_normalized(SYM_REF, "refs/heads/FoO", "refs/heads/FoO");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master", "refs/heads/master");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/pu", "refs/heads/pu");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/z", "refs/heads/z");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/FoO", "refs/heads/FoO");
 
 /* ValidTag */
-       ensure_refname_normalized(SYM_REF, "refs/tags/v1.0", "refs/tags/v1.0");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/tags/v1.0", "refs/tags/v1.0");
 
 /* NoLockSuffix */
-       ensure_refname_invalid(SYM_REF, "refs/heads/master.lock");
+       ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master.lock");
 
 /* NoDirectorySuffix */
-       ensure_refname_invalid(SYM_REF, "refs/heads/master/");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master/");
 
 /* NoSpace */
-       ensure_refname_invalid(SYM_REF, "refs/heads/i haz space");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/i haz space");
 
 /* NoAsciiControlCharacters */
        {
@@ -112,89 +164,153 @@ void test_refs_normalize__jgit_suite(void)
                        strncpy(buffer + 15, (const char *)&c, 1);
                        strncpy(buffer + 16, "er", 2);
                        buffer[18 - 1] = '\0';
-                       ensure_refname_invalid(SYM_REF, buffer);
+                       ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, buffer);
                }
        }
 
 /* NoBareDot */
-       ensure_refname_invalid(SYM_REF, "refs/heads/.");
-       ensure_refname_invalid(SYM_REF, "refs/heads/..");
-       ensure_refname_invalid(SYM_REF, "refs/heads/./master");
-       ensure_refname_invalid(SYM_REF, "refs/heads/../master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/./master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/../master");
 
 /* NoLeadingOrTrailingDot */
-       ensure_refname_invalid(SYM_REF, ".");
-       ensure_refname_invalid(SYM_REF, "refs/heads/.bar");
-       ensure_refname_invalid(SYM_REF, "refs/heads/..bar");
-       ensure_refname_invalid(SYM_REF, "refs/heads/bar.");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, ".");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.bar");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..bar");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/bar.");
 
 /* ContainsDot */
-       ensure_refname_normalized(SYM_REF, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
-       ensure_refname_invalid(SYM_REF, "refs/heads/master..pu");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master..pu");
 
 /* NoMagicRefCharacters */
-       ensure_refname_invalid(SYM_REF, "refs/heads/master^");
-       ensure_refname_invalid(SYM_REF, "refs/heads/^master");
-       ensure_refname_invalid(SYM_REF, "^refs/heads/master");
-
-       ensure_refname_invalid(SYM_REF, "refs/heads/master~");
-       ensure_refname_invalid(SYM_REF, "refs/heads/~master");
-       ensure_refname_invalid(SYM_REF, "~refs/heads/master");
-
-       ensure_refname_invalid(SYM_REF, "refs/heads/master:");
-       ensure_refname_invalid(SYM_REF, "refs/heads/:master");
-       ensure_refname_invalid(SYM_REF, ":refs/heads/master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master^");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/^master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "^refs/heads/master");
+
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master~");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/~master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "~refs/heads/master");
+
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master:");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/:master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, ":refs/heads/master");
 
 /* ShellGlob */
-       ensure_refname_invalid(SYM_REF, "refs/heads/master?");
-       ensure_refname_invalid(SYM_REF, "refs/heads/?master");
-       ensure_refname_invalid(SYM_REF, "?refs/heads/master");
-
-       ensure_refname_invalid(SYM_REF, "refs/heads/master[");
-       ensure_refname_invalid(SYM_REF, "refs/heads/[master");
-       ensure_refname_invalid(SYM_REF, "[refs/heads/master");
-
-       ensure_refname_invalid(SYM_REF, "refs/heads/master*");
-       ensure_refname_invalid(SYM_REF, "refs/heads/*master");
-       ensure_refname_invalid(SYM_REF, "*refs/heads/master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master?");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/?master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "?refs/heads/master");
+
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master[");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/[master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "[refs/heads/master");
+
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master*");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/*master");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "*refs/heads/master");
 
 /* ValidSpecialCharacters */
-       ensure_refname_normalized(SYM_REF, "refs/heads/!", "refs/heads/!");
-       ensure_refname_normalized(SYM_REF, "refs/heads/\"", "refs/heads/\"");
-       ensure_refname_normalized(SYM_REF, "refs/heads/#", "refs/heads/#");
-       ensure_refname_normalized(SYM_REF, "refs/heads/$", "refs/heads/$");
-       ensure_refname_normalized(SYM_REF, "refs/heads/%", "refs/heads/%");
-       ensure_refname_normalized(SYM_REF, "refs/heads/&", "refs/heads/&");
-       ensure_refname_normalized(SYM_REF, "refs/heads/'", "refs/heads/'");
-       ensure_refname_normalized(SYM_REF, "refs/heads/(", "refs/heads/(");
-       ensure_refname_normalized(SYM_REF, "refs/heads/)", "refs/heads/)");
-       ensure_refname_normalized(SYM_REF, "refs/heads/+", "refs/heads/+");
-       ensure_refname_normalized(SYM_REF, "refs/heads/,", "refs/heads/,");
-       ensure_refname_normalized(SYM_REF, "refs/heads/-", "refs/heads/-");
-       ensure_refname_normalized(SYM_REF, "refs/heads/;", "refs/heads/;");
-       ensure_refname_normalized(SYM_REF, "refs/heads/<", "refs/heads/<");
-       ensure_refname_normalized(SYM_REF, "refs/heads/=", "refs/heads/=");
-       ensure_refname_normalized(SYM_REF, "refs/heads/>", "refs/heads/>");
-       ensure_refname_normalized(SYM_REF, "refs/heads/@", "refs/heads/@");
-       ensure_refname_normalized(SYM_REF, "refs/heads/]", "refs/heads/]");
-       ensure_refname_normalized(SYM_REF, "refs/heads/_", "refs/heads/_");
-       ensure_refname_normalized(SYM_REF, "refs/heads/`", "refs/heads/`");
-       ensure_refname_normalized(SYM_REF, "refs/heads/{", "refs/heads/{");
-       ensure_refname_normalized(SYM_REF, "refs/heads/|", "refs/heads/|");
-       ensure_refname_normalized(SYM_REF, "refs/heads/}", "refs/heads/}");
+       ensure_refname_normalized
+               (GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/!", "refs/heads/!");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\"", "refs/heads/\"");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/#", "refs/heads/#");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/$", "refs/heads/$");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/%", "refs/heads/%");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/&", "refs/heads/&");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/'", "refs/heads/'");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/(", "refs/heads/(");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/)", "refs/heads/)");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/+", "refs/heads/+");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/,", "refs/heads/,");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/-", "refs/heads/-");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/;", "refs/heads/;");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/<", "refs/heads/<");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/=", "refs/heads/=");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/>", "refs/heads/>");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/@", "refs/heads/@");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/]", "refs/heads/]");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/_", "refs/heads/_");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/`", "refs/heads/`");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/{", "refs/heads/{");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/|", "refs/heads/|");
+       ensure_refname_normalized(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/}", "refs/heads/}");
 
        // This is valid on UNIX, but not on Windows
        // hence we make in invalid due to non-portability
        //
-       ensure_refname_invalid(SYM_REF, "refs/heads/\\");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\\");
 
 /* UnicodeNames */
        /*
         * Currently this fails.
-        * ensure_refname_normalized(SYM_REF, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
+        * ensure_refname_normalized(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
         */
 
 /* RefLogQueryIsValidRef */
-       ensure_refname_invalid(SYM_REF, "refs/heads/master@{1}");
-       ensure_refname_invalid(SYM_REF, "refs/heads/master@{1.hour.ago}");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1}");
+       ensure_refname_invalid(
+               GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1.hour.ago}");
+}
+
+void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_version(void)
+{
+       char buffer_out[21];
+
+       cl_git_pass(git_reference_normalize_name(
+               buffer_out, 21, "//refs//heads/long///name", GIT_REF_FORMAT_NORMAL));
+       cl_git_fail(git_reference_normalize_name(
+               buffer_out, 20, "//refs//heads/long///name", GIT_REF_FORMAT_NORMAL));
 }