From bd370b14fefdba3844a9bf0bbf87171ca48f49be Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 30 Dec 2011 15:00:14 -0800 Subject: [PATCH] Improved gitattributes macro implementation This updates to implementation of gitattribute macros to be much more similar to core git (albeit not 100%) and to handle expansion of macros within macros, etc. It also cleans up the refcounting usage with macros to be much cleaner. Also, this adds a new vector function `git_vector_insert_sorted()` which allows you to maintain a sorted list as you go. In order to write that function, this changes the function `git__bsearch()` to take a somewhat different set of parameters, although the core functionality is still the same. --- src/attr_file.c | 71 +++++----- src/util.c | 36 +++-- src/util.h | 9 +- src/vector.c | 47 ++++++- src/vector.h | 3 + tests-clay/attr/repo.c | 54 +++++++- tests-clay/clay.h | 4 + tests-clay/clay_main.c | 14 +- tests-clay/core/vector.c | 125 ++++++++++++++++++ tests/resources/attr/.gitted/index | Bin 1304 -> 1376 bytes tests/resources/attr/.gitted/logs/HEAD | Bin 332 -> 491 bytes .../attr/.gitted/logs/refs/heads/master | Bin 332 -> 491 bytes .../2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a | Bin 0 -> 269 bytes .../58/19a185d77b03325aaf87cafc771db36f6ddca7 | Bin 0 -> 19 bytes .../a5/d76cad53f66f1312bd995909a5bab3c0820770 | Bin 0 -> 163 bytes .../d5/7da33c16b14326ecb05d19bbea908f5e4c47d9 | Bin 0 -> 379 bytes .../resources/attr/.gitted/refs/heads/master | Bin 41 -> 41 bytes tests/resources/attr/gitattributes | Bin 162 -> 602 bytes tests/resources/attr/macro_bad | Bin 0 -> 4 bytes 19 files changed, 297 insertions(+), 66 deletions(-) create mode 100644 tests/resources/attr/.gitted/objects/2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a create mode 100644 tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7 create mode 100644 tests/resources/attr/.gitted/objects/a5/d76cad53f66f1312bd995909a5bab3c0820770 create mode 100644 tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9 create mode 100644 tests/resources/attr/macro_bad diff --git a/src/attr_file.c b/src/attr_file.c index a1379054b..fe8844e2d 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -12,17 +12,9 @@ static void git_attr_rule__clear(git_attr_rule *rule); int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro) { - unsigned int i; - git_attr_assignment *assign; - if (macro->assigns.length == 0) return git__throw(GIT_EMISSINGOBJDATA, "git attribute macro with no values"); - git_vector_foreach(¯o->assigns, i, assign) { - GIT_REFCOUNT_OWN(assign, macro); - GIT_REFCOUNT_INC(assign); - } - return git_hashtable_insert( repo->attrcache.macros, macro->match.pattern, macro); } @@ -358,7 +350,7 @@ static int sort_by_hash_and_name(const void *a_raw, const void *b_raw) return strcmp(b->name, a->name); } -static void free_assign(git_attr_assignment *assign) +static void git_attr_assignment__free(git_attr_assignment *assign) { git__free(assign->name); assign->name = NULL; @@ -371,6 +363,16 @@ static void free_assign(git_attr_assignment *assign) git__free(assign); } +static int merge_assignments(void **old_raw, void *new_raw) +{ + git_attr_assignment **old = (git_attr_assignment **)old_raw; + git_attr_assignment *new = (git_attr_assignment *)new_raw; + + GIT_REFCOUNT_DEC(*old, git_attr_assignment__free); + *old = new; + return GIT_EEXISTS; +} + int git_attr_assignment__parse( git_repository *repo, git_vector *assigns, @@ -382,6 +384,8 @@ int git_attr_assignment__parse( assert(assigns && !assigns->length); + assigns->_cmp = sort_by_hash_and_name; + while (*scan && *scan != '\n' && error == GIT_SUCCESS) { const char *name_start, *value_start; @@ -395,6 +399,7 @@ int git_attr_assignment__parse( error = GIT_ENOMEM; break; } + GIT_REFCOUNT_INC(assign); } assign->name_hash = 5381; @@ -449,8 +454,8 @@ int git_attr_assignment__parse( } } - /* expand macros (if given a repo) */ - if (repo != NULL) { + /* expand macros (if given a repo with a macro cache) */ + if (repo != NULL && assign->value == GIT_ATTR_TRUE) { git_attr_rule *macro = git_hashtable_lookup(repo->attrcache.macros, assign->name); @@ -458,30 +463,25 @@ int git_attr_assignment__parse( unsigned int i; git_attr_assignment *massign; - /* issue warning: if assign->value != GIT_ATTR_TRUE */ - - git__free(assign->name); - assign->name = NULL; - if (assign->is_allocated) { - git__free((void *)assign->value); - assign->value = NULL; - } - git_vector_foreach(¯o->assigns, i, massign) { - error = git_vector_insert(assigns, massign); - if (error != GIT_SUCCESS) - break; - GIT_REFCOUNT_INC(&massign->rc); - } + GIT_REFCOUNT_INC(massign); - /* continue to next assignment */ - continue; + error = git_vector_insert_sorted( + assigns, massign, &merge_assignments); + + if (error == GIT_EEXISTS) + error = GIT_SUCCESS; + else if (error != GIT_SUCCESS) + break; + } } } /* insert allocated assign into vector */ - error = git_vector_insert(assigns, assign); - if (error < GIT_SUCCESS) + error = git_vector_insert_sorted(assigns, assign, &merge_assignments); + if (error == GIT_EEXISTS) + error = GIT_SUCCESS; + else if (error < GIT_SUCCESS) break; /* clear assign since it is now "owned" by the vector */ @@ -490,13 +490,9 @@ int git_attr_assignment__parse( if (!assigns->length) error = git__throw(GIT_ENOTFOUND, "No attribute assignments found for rule"); - else { - assigns->_cmp = sort_by_hash_and_name; - git_vector_sort(assigns); - } if (assign != NULL) - free_assign(assign); + git_attr_assignment__free(assign); while (*scan && *scan != '\n') scan++; if (*scan == '\n') scan++; @@ -518,11 +514,8 @@ static void git_attr_rule__clear(git_attr_rule *rule) rule->match.pattern = NULL; rule->match.length = 0; - git_vector_foreach(&rule->assigns, i, assign) { - if (GIT_REFCOUNT_OWNER(assign) == rule) - GIT_REFCOUNT_OWN(assign, NULL); - GIT_REFCOUNT_DEC(assign, free_assign); - } + git_vector_foreach(&rule->assigns, i, assign) + GIT_REFCOUNT_DEC(assign, git_attr_assignment__free); git_vector_free(&rule->assigns); } diff --git a/src/util.c b/src/util.c index b3af7ffd8..1ca9d850c 100644 --- a/src/util.c +++ b/src/util.c @@ -348,22 +348,30 @@ uint32_t git__hash(const void *key, int len, uint32_t seed) * Copyright (c) 1990 Regents of the University of California. * All rights reserved. */ -void **git__bsearch(const void *key, void **base, size_t nmemb, int (*compar)(const void *, const void *)) +int git__bsearch( + void **array, + size_t array_len, + const void *key, + int (*compare)(const void *, const void *), + size_t *position) { - int lim, cmp; - void **p; + int lim, cmp; + void **part, **base = array; - for (lim = nmemb; lim != 0; lim >>= 1) { - p = base + (lim >> 1); - cmp = (*compar)(key, *p); - if (cmp > 0) { /* key > p: move right */ - base = p + 1; - lim--; - } else if (cmp == 0) { - return (void **)p; - } /* else move left */ - } - return NULL; + for (lim = array_len; lim != 0; lim >>= 1) { + part = base + (lim >> 1); + cmp = (*compare)(key, *part); + if (cmp == 0) { + *position = (part - array); + return GIT_SUCCESS; + } else if (cmp > 0) { /* key > p; take right partition */ + base = part + 1; + lim--; + } /* else take left partition */ + } + + *position = (base - array); + return GIT_ENOTFOUND; } /** diff --git a/src/util.h b/src/util.h index 4b1104b7b..2367bb5f3 100644 --- a/src/util.h +++ b/src/util.h @@ -105,8 +105,13 @@ extern void git__strtolower(char *str); extern int git__fnmatch(const char *pattern, const char *name, int flags); extern void git__tsort(void **dst, size_t size, int (*cmp)(const void *, const void *)); -extern void **git__bsearch(const void *key, void **base, size_t nmemb, - int (*compar)(const void *, const void *)); + +extern int git__bsearch( + void **array, + size_t array_len, + const void *key, + int (*compare)(const void *, const void *), + size_t *position); extern int git__strcmp_cb(const void *a, const void *b); diff --git a/src/vector.c b/src/vector.c index e745d77dd..593d037d4 100644 --- a/src/vector.c +++ b/src/vector.c @@ -74,6 +74,45 @@ int git_vector_insert(git_vector *v, void *element) return GIT_SUCCESS; } +int git_vector_insert_sorted(git_vector *v, void *element, int (*on_dup)(void **old, void *new)) +{ + int error = GIT_SUCCESS; + size_t pos; + + assert(v && v->_cmp); + + if (!v->sorted) + git_vector_sort(v); + + if (v->length >= v->_alloc_size) { + if (resize_vector(v) < 0) + return GIT_ENOMEM; + } + + error = git__bsearch(v->contents, v->length, element, v->_cmp, &pos); + + /* If we found the element and have a duplicate handler callback, + * invoke it. If it returns an error, then cancel insert, otherwise + * proceed with normal insert. + */ + if (error == GIT_SUCCESS && on_dup != NULL) { + error = on_dup(&v->contents[pos], element); + if (error != GIT_SUCCESS) + return error; + } + + /* shift elements to the right */ + if (pos < v->length) { + memmove(v->contents + pos + 1, v->contents + pos, + (v->length - pos) * sizeof(void *)); + } + + v->contents[pos] = element; + v->length++; + + return GIT_SUCCESS; +} + void git_vector_sort(git_vector *v) { assert(v); @@ -87,7 +126,7 @@ void git_vector_sort(git_vector *v) int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key) { - void **find; + size_t pos; assert(v && key && key_lookup); @@ -97,9 +136,9 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke git_vector_sort(v); - find = git__bsearch(key, v->contents, v->length, key_lookup); - if (find != NULL) - return (int)(find - v->contents); + if (git__bsearch(v->contents, v->length, key, key_lookup, + &pos) == GIT_SUCCESS) + return (int)pos; return git__throw(GIT_ENOTFOUND, "Can't find element"); } diff --git a/src/vector.h b/src/vector.h index 4c053e6ae..9ee3c9ed5 100644 --- a/src/vector.h +++ b/src/vector.h @@ -45,6 +45,9 @@ GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position) for ((iter) = (v)->length; (iter) > 0 && ((elem) = (v)->contents[(iter)-1], 1); (iter)-- ) int git_vector_insert(git_vector *v, void *element); +int git_vector_insert_sorted(git_vector *v, void *element, + int (*on_dup)(void **old, void *new)); int git_vector_remove(git_vector *v, unsigned int idx); void git_vector_uniq(git_vector *v); + #endif diff --git a/tests-clay/attr/repo.c b/tests-clay/attr/repo.c index e80e24dbf..f87e7bf55 100644 --- a/tests-clay/attr/repo.c +++ b/tests-clay/attr/repo.c @@ -40,8 +40,11 @@ void test_attr_repo__get_one(void) { "root_test2", "repoattr", GIT_ATTR_TRUE }, { "root_test2", "rootattr", GIT_ATTR_FALSE }, { "root_test2", "missingattr", NULL }, + { "root_test2", "multiattr", GIT_ATTR_FALSE }, { "root_test3", "repoattr", GIT_ATTR_TRUE }, { "root_test3", "rootattr", NULL }, + { "root_test3", "multiattr", "3" }, + { "root_test3", "multi2", NULL }, { "subdir/subdir_test1", "repoattr", GIT_ATTR_TRUE }, { "subdir/subdir_test1", "rootattr", GIT_ATTR_TRUE }, { "subdir/subdir_test1", "missingattr", NULL }, @@ -166,21 +169,68 @@ void test_attr_repo__macros(void) { const char *names[5] = { "rootattr", "binary", "diff", "crlf", "frotz" }; const char *names2[5] = { "mymacro", "positive", "negative", "rootattr", "another" }; + const char *names3[3] = { "macro2", "multi2", "multi3" }; const char *values[5]; cl_git_pass(git_attr_get_many(g_repo, "binfile", 5, names, values)); cl_assert(values[0] == GIT_ATTR_TRUE); - cl_assert(values[1] == NULL); + cl_assert(values[1] == GIT_ATTR_TRUE); cl_assert(values[2] == GIT_ATTR_FALSE); cl_assert(values[3] == GIT_ATTR_FALSE); cl_assert(values[4] == NULL); cl_git_pass(git_attr_get_many(g_repo, "macro_test", 5, names2, values)); - cl_assert(values[0] == NULL); + cl_assert(values[0] == GIT_ATTR_TRUE); cl_assert(values[1] == GIT_ATTR_TRUE); cl_assert(values[2] == GIT_ATTR_FALSE); cl_assert(values[3] == NULL); cl_assert_strequal("77", values[4]); + + cl_git_pass(git_attr_get_many(g_repo, "macro_test", 3, names3, values)); + + cl_assert(values[0] == GIT_ATTR_TRUE); + cl_assert(values[1] == GIT_ATTR_FALSE); + cl_assert_strequal("answer", values[2]); +} + +void test_attr_repo__bad_macros(void) +{ + const char *names[6] = { "rootattr", "positive", "negative", + "firstmacro", "secondmacro", "thirdmacro" }; + const char *values[6]; + + cl_git_pass(git_attr_get_many(g_repo, "macro_bad", 6, names, values)); + + /* these three just confirm that the "mymacro" rule ran */ + cl_assert(values[0] == NULL); + cl_assert(values[1] == GIT_ATTR_TRUE); + cl_assert(values[2] == GIT_ATTR_FALSE); + + /* file contains: + * # let's try some malicious macro defs + * [attr]firstmacro -thirdmacro -secondmacro + * [attr]secondmacro firstmacro -firstmacro + * [attr]thirdmacro secondmacro=hahaha -firstmacro + * macro_bad firstmacro secondmacro thirdmacro + * + * firstmacro assignment list ends up with: + * -thirdmacro -secondmacro + * secondmacro assignment list expands "firstmacro" and ends up with: + * -thirdmacro -secondmacro -firstmacro + * thirdmacro assignment don't expand so list ends up with: + * secondmacro="hahaha" + * + * macro_bad assignment list ends up with: + * -thirdmacro -secondmacro firstmacro && + * -thirdmacro -secondmacro -firstmacro secondmacro && + * secondmacro="hahaha" thirdmacro + * + * so summary results should be: + * -firstmacro secondmacro="hahaha" thirdmacro + */ + cl_assert(values[3] == GIT_ATTR_FALSE); + cl_assert_strequal("hahaha", values[4]); + cl_assert(values[5] == GIT_ATTR_TRUE); } diff --git a/tests-clay/clay.h b/tests-clay/clay.h index 4a57926bf..e4a413513 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -68,6 +68,7 @@ extern void test_attr_lookup__check_attr_examples(void); extern void test_attr_lookup__from_buffer(void); extern void test_attr_lookup__match_variants(void); extern void test_attr_lookup__simple(void); +extern void test_attr_repo__bad_macros(void); extern void test_attr_repo__cleanup(void); extern void test_attr_repo__foreach(void); extern void test_attr_repo__get_many(void); @@ -141,6 +142,9 @@ extern void test_core_strtol__int64(void); extern void test_core_vector__0(void); extern void test_core_vector__1(void); extern void test_core_vector__2(void); +extern void test_core_vector__3(void); +extern void test_core_vector__4(void); +extern void test_core_vector__5(void); extern void test_index_rename__single_file(void); extern void test_network_remotes__cleanup(void); extern void test_network_remotes__fnmatch(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index ce881e45d..a3dce81cf 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -122,7 +122,8 @@ static const struct clay_func _clay_cb_attr_lookup[] = { {"simple", &test_attr_lookup__simple} }; static const struct clay_func _clay_cb_attr_repo[] = { - {"foreach", &test_attr_repo__foreach}, + {"bad_macros", &test_attr_repo__bad_macros}, + {"foreach", &test_attr_repo__foreach}, {"get_many", &test_attr_repo__get_many}, {"get_one", &test_attr_repo__get_one}, {"macros", &test_attr_repo__macros}, @@ -214,7 +215,10 @@ static const struct clay_func _clay_cb_core_strtol[] = { static const struct clay_func _clay_cb_core_vector[] = { {"0", &test_core_vector__0}, {"1", &test_core_vector__1}, - {"2", &test_core_vector__2} + {"2", &test_core_vector__2}, + {"3", &test_core_vector__3}, + {"4", &test_core_vector__4}, + {"5", &test_core_vector__5} }; static const struct clay_func _clay_cb_index_rename[] = { {"single_file", &test_index_rename__single_file} @@ -338,7 +342,7 @@ static const struct clay_suite _clay_suites[] = { "attr::repo", {"initialize", &test_attr_repo__initialize}, {"cleanup", &test_attr_repo__cleanup}, - _clay_cb_attr_repo, 5 + _clay_cb_attr_repo, 6 }, { "buf::basic", @@ -428,7 +432,7 @@ static const struct clay_suite _clay_suites[] = { "core::vector", {NULL, NULL}, {NULL, NULL}, - _clay_cb_core_vector, 3 + _clay_cb_core_vector, 6 }, { "index::rename", @@ -559,7 +563,7 @@ static const struct clay_suite _clay_suites[] = { }; static size_t _clay_suite_count = 39; -static size_t _clay_callback_count = 134; +static size_t _clay_callback_count = 138; /* Core test functions */ static void diff --git a/tests-clay/core/vector.c b/tests-clay/core/vector.c index b8a853c60..fdcfb3a77 100644 --- a/tests-clay/core/vector.c +++ b/tests-clay/core/vector.c @@ -64,3 +64,128 @@ void test_core_vector__2(void) } +static int compare_them(const void *a, const void *b) +{ + return (int)((long)a - (long)b); +} + +/* insert_sorted */ +void test_core_vector__3(void) +{ + git_vector x; + long i; + git_vector_init(&x, 1, &compare_them); + + for (i = 0; i < 10; i += 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 9; i > 0; i -= 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + cl_assert(x.length == 10); + for (i = 0; i < 10; ++i) { + cl_assert(git_vector_get(&x, i) == (void*)(i + 1)); + } + + git_vector_free(&x); +} + +/* insert_sorted with duplicates */ +void test_core_vector__4(void) +{ + git_vector x; + long i; + git_vector_init(&x, 1, &compare_them); + + for (i = 0; i < 10; i += 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 9; i > 0; i -= 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 0; i < 10; i += 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + for (i = 9; i > 0; i -= 2) { + git_vector_insert_sorted(&x, (void*)(i + 1), NULL); + } + + cl_assert(x.length == 20); + for (i = 0; i < 20; ++i) { + cl_assert(git_vector_get(&x, i) == (void*)(i / 2 + 1)); + } + + git_vector_free(&x); +} + +typedef struct { + int content; + int count; +} my_struct; + +static int _struct_count = 0; + +static int compare_structs(const void *a, const void *b) +{ + return ((const my_struct *)a)->content - + ((const my_struct *)b)->content; +} + +static int merge_structs(void **old_raw, void *new) +{ + my_struct *old = *(my_struct **)old_raw; + cl_assert(((my_struct *)old)->content == ((my_struct *)new)->content); + ((my_struct *)old)->count += 1; + git__free(new); + _struct_count--; + return GIT_EEXISTS; +} + +static my_struct *alloc_struct(int value) +{ + my_struct *st = git__malloc(sizeof(my_struct)); + st->content = value; + st->count = 0; + _struct_count++; + return st; +} + +/* insert_sorted with duplicates and special handling */ +void test_core_vector__5(void) +{ + git_vector x; + int i; + + git_vector_init(&x, 1, &compare_structs); + + for (i = 0; i < 10; i += 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + for (i = 9; i > 0; i -= 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + cl_assert(x.length == 10); + cl_assert(_struct_count == 10); + + for (i = 0; i < 10; i += 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + for (i = 9; i > 0; i -= 2) + git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); + + cl_assert(x.length == 10); + cl_assert(_struct_count == 10); + + for (i = 0; i < 10; ++i) { + cl_assert(((my_struct *)git_vector_get(&x, i))->content == i); + git__free(git_vector_get(&x, i)); + _struct_count--; + } + + git_vector_free(&x); +} diff --git a/tests/resources/attr/.gitted/index b/tests/resources/attr/.gitted/index index 9c5907386ff2aaed7325a3059c4256e1fee493d8..c52747e0b6c9a457a28c9b9fea098f0fa2e59c48 100644 GIT binary patch delta 609 zcmbQi^?*yo#WTp6fq{Vuhz0%r$Zi4B3^1AxByMRqX<~_?ICiPY6ZhbfnlhP%5trQ5 z$vz-CIU$H`5E^2e3IF6NjE43940eI#pfprYfPtZL2?GP;SD>5-&~Z`P4oBB4jNIV2 z;u8Nqv$H=oOwQcs#lV}MS&~>%Qk0ogT9R4}GKRtLuis2$8f=~w+i6tu7+4}C7q(un zW;Qa2THk)^Pr2;o{MlM+*aL4(!Nf|KtsTH*+!X_IxBaLG-dT!T|? z#^f_Nc zeVmwMh(qej#4Wg_K2Q8(DE@n!DcD*l4Ytv|?)j?#AZPFnLrgcmH{y6`i!{v(P2P=1b E0Pj<}ki}DppQj1H9xd1@}91j2h delta 7 OcmaFOe1>U*4<}ki}DppQj1H9xd1@}91j2h delta 7 OcmaFOe1>U*4W25m5Xi_$NJ-n}PV&a+7BAVG@ zW_FC4oPzh)=IIFJ93wM{2+piMH&Fj2TR1#OW$a)kT>(H9KVe2%1gfs82IoK_h4(JX z$oV?4`Msxwm27126xvKjt$a(86*mQbSi?>@q?muVNzY{L1?qjj_=s_z^D<*c4!)c> zY`!(rR$p*M`=73oBWzl-MbP`)i%*f5cy`?6pXt=R;%w1cF*55RVEi*gILx^XX zG{1OYTEM$m!;F*ZjJx`PV%=U3KJOk3c}{H2qoF=yuRCYckd*}krEAAoSi}?_IbwW7 Ts(x13mnnr1cE9)m@y^_p7~_N= literal 0 HcmV?d00001 diff --git a/tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7 b/tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7 new file mode 100644 index 0000000000000000000000000000000000000000..fe34eb63a24a5a6f018ec69a08111506d58efe31 GIT binary patch literal 19 acmbMEHKeni? RGgL~w!Q?TA_yRN8N?76vP4)l) literal 0 HcmV?d00001 diff --git a/tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9 b/tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9 new file mode 100644 index 0000000000000000000000000000000000000000..b96d40c24ed941d514f427c31ee6d382a7ee0286 GIT binary patch literal 379 zcmV->0fhc|0V^p=O;s>8Fk>(@FfcPQQAjK)DKcOP&F^Wd?(mk!9N4*WOR^9COxTOtMRg|A! z5)V>j$lxj>Rk^&v>FBIvr76rxTz=lq{cO=y84;z*m?%{ydLL(xjBkB8K@}xYJ7SKI0CXzW&_0iQ94~^f28-R$#=Ssd-OB Z=jF_ofz9h~9dng6ZV8>^4FLUm%U%!i#s&ZY literal 0 HcmV?d00001 diff --git a/tests/resources/attr/.gitted/refs/heads/master b/tests/resources/attr/.gitted/refs/heads/master index 1049fe4b741ea8047c4a5860a936a01c3317b93a..0516af2d228cd82542634c323befefb9f6ced7a7 100644 GIT binary patch literal 41 vcmV~$$qfK72m`Qxr%6G9G7g8>e}vk}aqArFn(fsqH4zL%va+=C1nxK=@UaTX literal 41 ucmV~$(E$J;1O>qVrV$<)hh+Z|x--JroaOVB_jC&*L(qa-WEm`)-o8HM_6o!R diff --git a/tests/resources/attr/gitattributes b/tests/resources/attr/gitattributes index 94da4faa0a6bfb8ee6ccf7153801a69202b31857..2b40c5aca159b04ea8d20ffe36cdf8b09369b14a 100644 GIT binary patch literal 602 zcmZut%Wi`(5Ip0r*rleXQD+Hb$&CCuy13AaY zOd^6SE6*LYf5{$BPjb+9)~jj&poyO_BW(hQv1w-KU_c7*x2Pk{eP#W7PY;RgWbjnl zLPxE9%aVk<3O}u3C!BK3zuTl|()I@Jv0uE$xDT@#9Ld3_^P2TTL2K0w6FUAhNzSlq z(K=of$;(CTDKVoo3-^|r-(Asl}317cCy AJ^%m! delta 9 Qcmcb`vWRg)?8Gmw02FHkIRF3v diff --git a/tests/resources/attr/macro_bad b/tests/resources/attr/macro_bad new file mode 100644 index 0000000000000000000000000000000000000000..5819a185d77b03325aaf87cafc771db36f6ddca7 GIT binary patch literal 4 LcmYew&*uUF1Hl1H literal 0 HcmV?d00001