summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/attr_file.c67
-rw-r--r--src/util.c38
-rw-r--r--src/util.h9
-rw-r--r--src/vector.c47
-rw-r--r--src/vector.h3
-rw-r--r--tests-clay/attr/repo.c54
-rw-r--r--tests-clay/clay.h4
-rw-r--r--tests-clay/clay_main.c14
-rw-r--r--tests-clay/core/vector.c125
-rw-r--r--tests/resources/attr/.gitted/indexbin1304 -> 1376 bytes
-rw-r--r--tests/resources/attr/.gitted/logs/HEAD1
-rw-r--r--tests/resources/attr/.gitted/logs/refs/heads/master1
-rw-r--r--tests/resources/attr/.gitted/objects/2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a1
-rw-r--r--tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7bin0 -> 19 bytes
-rw-r--r--tests/resources/attr/.gitted/objects/a5/d76cad53f66f1312bd995909a5bab3c08207704
-rw-r--r--tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9bin0 -> 379 bytes
-rw-r--r--tests/resources/attr/.gitted/refs/heads/master2
-rw-r--r--tests/resources/attr/gitattributes17
-rw-r--r--tests/resources/attr/macro_bad1
19 files changed, 322 insertions, 66 deletions
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(&macro->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_vector_foreach(&macro->assigns, i, massign) {
+ GIT_REFCOUNT_INC(massign);
- git__free(assign->name);
- assign->name = NULL;
- if (assign->is_allocated) {
- git__free((void *)assign->value);
- assign->value = NULL;
- }
+ error = git_vector_insert_sorted(
+ assigns, massign, &merge_assignments);
- git_vector_foreach(&macro->assigns, i, massign) {
- error = git_vector_insert(assigns, massign);
- if (error != GIT_SUCCESS)
+ if (error == GIT_EEXISTS)
+ error = GIT_SUCCESS;
+ else if (error != GIT_SUCCESS)
break;
- GIT_REFCOUNT_INC(&massign->rc);
}
-
- /* continue to next assignment */
- continue;
}
}
/* 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;
-
- 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;
+ int lim, cmp;
+ void **part, **base = array;
+
+ 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 9c5907386..c52747e0b 100644
--- a/tests/resources/attr/.gitted/index
+++ b/tests/resources/attr/.gitted/index
Binary files differ
diff --git a/tests/resources/attr/.gitted/logs/HEAD b/tests/resources/attr/.gitted/logs/HEAD
index 3c4045173..f518a465a 100644
--- a/tests/resources/attr/.gitted/logs/HEAD
+++ b/tests/resources/attr/.gitted/logs/HEAD
@@ -1,2 +1,3 @@
0000000000000000000000000000000000000000 6bab5c79cd5140d0f800917f550eb2a3dc32b0da Russell Belfer <arrbee@arrbee.com> 1324416995 -0800 commit (initial): initial test data
6bab5c79cd5140d0f800917f550eb2a3dc32b0da 605812ab7fe421fdd325a935d35cb06a9234a7d7 Russell Belfer <arrbee@arrbee.com> 1325143098 -0800 commit: latest test updates
+605812ab7fe421fdd325a935d35cb06a9234a7d7 a5d76cad53f66f1312bd995909a5bab3c0820770 Russell Belfer <arrbee@arrbee.com> 1325281762 -0800 commit: more macro tests
diff --git a/tests/resources/attr/.gitted/logs/refs/heads/master b/tests/resources/attr/.gitted/logs/refs/heads/master
index 3c4045173..f518a465a 100644
--- a/tests/resources/attr/.gitted/logs/refs/heads/master
+++ b/tests/resources/attr/.gitted/logs/refs/heads/master
@@ -1,2 +1,3 @@
0000000000000000000000000000000000000000 6bab5c79cd5140d0f800917f550eb2a3dc32b0da Russell Belfer <arrbee@arrbee.com> 1324416995 -0800 commit (initial): initial test data
6bab5c79cd5140d0f800917f550eb2a3dc32b0da 605812ab7fe421fdd325a935d35cb06a9234a7d7 Russell Belfer <arrbee@arrbee.com> 1325143098 -0800 commit: latest test updates
+605812ab7fe421fdd325a935d35cb06a9234a7d7 a5d76cad53f66f1312bd995909a5bab3c0820770 Russell Belfer <arrbee@arrbee.com> 1325281762 -0800 commit: more macro tests
diff --git a/tests/resources/attr/.gitted/objects/2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a b/tests/resources/attr/.gitted/objects/2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a
new file mode 100644
index 000000000..0e2368069
--- /dev/null
+++ b/tests/resources/attr/.gitted/objects/2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a
@@ -0,0 +1 @@
+xmPj0=P8ZSc hR6{=ob"afv#3ά=7P%[8<He`&]@?aFZ@!.:ldLG|K7~XN8Id}q2cG7l5V_pE#lZGMt[J½&hu][4-3;Cg4x`ZYÌ錻b^> yNlͣ>c;gӐkYX9b|D~Vؗ)vܕ \ No newline at end of file
diff --git a/tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7 b/tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7
new file mode 100644
index 000000000..fe34eb63a
--- /dev/null
+++ b/tests/resources/attr/.gitted/objects/58/19a185d77b03325aaf87cafc771db36f6ddca7
Binary files differ
diff --git a/tests/resources/attr/.gitted/objects/a5/d76cad53f66f1312bd995909a5bab3c0820770 b/tests/resources/attr/.gitted/objects/a5/d76cad53f66f1312bd995909a5bab3c0820770
new file mode 100644
index 000000000..cd6a389f9
--- /dev/null
+++ b/tests/resources/attr/.gitted/objects/a5/d76cad53f66f1312bd995909a5bab3c0820770
@@ -0,0 +1,4 @@
+x]
+!E{vB>!"ZB;u3Cm {.7Z4avfgBLEeP;NQڬBLAnŲI 5I)M6ZQ[
+h3e:
+ }u};|)z&pbq?3TJ13JX \ No newline at end of file
diff --git a/tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9 b/tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9
new file mode 100644
index 000000000..b96d40c24
--- /dev/null
+++ b/tests/resources/attr/.gitted/objects/d5/7da33c16b14326ecb05d19bbea908f5e4c47d9
Binary files differ
diff --git a/tests/resources/attr/.gitted/refs/heads/master b/tests/resources/attr/.gitted/refs/heads/master
index 1049fe4b7..0516af2d2 100644
--- a/tests/resources/attr/.gitted/refs/heads/master
+++ b/tests/resources/attr/.gitted/refs/heads/master
@@ -1 +1 @@
-605812ab7fe421fdd325a935d35cb06a9234a7d7
+a5d76cad53f66f1312bd995909a5bab3c0820770
diff --git a/tests/resources/attr/gitattributes b/tests/resources/attr/gitattributes
index 94da4faa0..2b40c5aca 100644
--- a/tests/resources/attr/gitattributes
+++ b/tests/resources/attr/gitattributes
@@ -3,5 +3,22 @@ root_test2 -rootattr
root_test3 !rootattr
binfile binary
abc foo bar baz
+
+root_test2 multiattr
+root_test3 multi2=foo
+
+root_test3 multiattr=1 multiattr=2 multiattr=3 multi2=abc !multi2
+root_test2 multiattr=string -multiattr
+
[attr]mymacro positive -negative !rootattr
macro* mymacro another=77
+
+[attr]macro2 multi2 -multi2 multi3 !multi3 multi3=answer
+macro* macro2 macro2 macro2
+
+# let's try some malicious macro defs
+[attr]firstmacro -thirdmacro -secondmacro
+[attr]secondmacro firstmacro -firstmacro
+[attr]thirdmacro secondmacro=hahaha
+
+macro_bad firstmacro secondmacro thirdmacro
diff --git a/tests/resources/attr/macro_bad b/tests/resources/attr/macro_bad
new file mode 100644
index 000000000..5819a185d
--- /dev/null
+++ b/tests/resources/attr/macro_bad
@@ -0,0 +1 @@
+boo