diff --git a/src/commit.c b/src/commit.c index a1a5bf7f5..6b0b66190 100644 --- a/src/commit.c +++ b/src/commit.c @@ -29,14 +29,22 @@ #include "git/odb.h" #define COMMIT_PRINT(commit) {\ - char oid[41]; oid[40] = 0;\ - git_oid_fmt(oid, &commit->object.id);\ - printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\ + char oid[41]; oid[40] = 0;\ + git_oid_fmt(oid, &commit->object.id);\ + printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\ } void git_commit__free(git_commit *commit) { git_commit_list_clear(&commit->parents, 0); + + if (commit->odb_open) + git_obj_close(&commit->odb_object); + + free(commit->author); + free(commit->committer); + free(commit->message); + free(commit->message_short); free(commit); } @@ -69,7 +77,7 @@ git_commit *git_commit_parse(git_revpool *pool, const git_oid *id) if ((commit = git_commit_lookup(pool, id)) == NULL) return NULL; - if (git_commit_parse_existing(commit) < 0) + if (git_commit__parse_basic(commit) < 0) goto error_cleanup; return commit; @@ -79,28 +87,49 @@ error_cleanup: return NULL; } -int git_commit_parse_existing(git_commit *commit) +int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db_object) { int error = 0; - git_obj commit_obj; - if (commit->parsed) + if (!commit->odb_open) { + error = git_odb_read(&commit->odb_object, commit->object.pool->db, &commit->object.id); + if (error < 0) + return error; + + if (commit->odb_object.type != GIT_OBJ_COMMIT) { + git_obj_close(&commit->odb_object); + return GIT_EOBJTYPE; + } + + commit->odb_open = 1; + } + + error = git_commit__parse_buffer(commit, + commit->odb_object.data, commit->odb_object.len, parse_flags); + + if (close_db_object) { + git_obj_close(&commit->odb_object); + commit->odb_open = 0; + } + + return error; +} + +int git_commit__parse_basic(git_commit *commit) +{ + int error; + + if (commit->basic_parse) return 0; - error = git_odb_read(&commit_obj, commit->object.pool->db, &commit->object.id); + error = git_commit__parse(commit, + (GIT_COMMIT_TREE | GIT_COMMIT_PARENTS | GIT_COMMIT_TIME), 1); + if (error < 0) return error; - if (commit_obj.type != GIT_OBJ_COMMIT) { - error = GIT_EOBJTYPE; - goto cleanup; - } - - error = git_commit__parse_buffer(commit, commit_obj.data, commit_obj.len); - -cleanup: - git_obj_close(&commit_obj); - return error; + commit->basic_parse = 1; + return 0; } git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id) @@ -131,35 +160,67 @@ git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id) return commit; } -int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end) +int git_commit__parse_person(git_commit_person *person, char **buffer_out, + const char *buffer_end, const char *header) { - if (memcmp(buffer, "author ", 7) != 0) + const size_t header_len = strlen(header); + + int i; + char *buffer = *buffer_out; + char *line_end, *name, *email; + + line_end = memchr(buffer, '\n', buffer_end - buffer); + if (!line_end) return GIT_EOBJCORRUPTED; - buffer = memchr(buffer, '\n', buffer_end - buffer); - if (!buffer || ++buffer >= buffer_end) + if (buffer + (header_len + 1) > line_end) return GIT_EOBJCORRUPTED; - if (memcmp(buffer, "committer ", 10) != 0) + if (memcmp(buffer, header, header_len) != 0) return GIT_EOBJCORRUPTED; - buffer = memchr(buffer, '>', buffer_end - buffer); - if (!buffer || ++buffer >= buffer_end) + buffer += header_len; + + + /* Parse name field */ + for (i = 0, name = person->name; + i < 64 && buffer < line_end && *buffer != '<'; + ++i) + *name++ = *buffer++; + + *(name - 1) = 0; + + while (buffer < line_end && *buffer != '<') + buffer++; + + if (++buffer >= line_end) return GIT_EOBJCORRUPTED; - *commit_time = strtol(buffer, &buffer, 10); + /* Parse email field */ + for (i = 0, email = person->email; + i < 64 && buffer < line_end && *buffer != '>'; + ++i) + *email++ = *buffer++; - if (*commit_time == 0) + *email = 0; + + while (buffer < line_end && *buffer != '>') + buffer++; + + if (++buffer >= line_end) return GIT_EOBJCORRUPTED; - buffer = memchr(buffer, '\n', buffer_end - buffer); - if (!buffer || ++buffer >= buffer_end) + person->time = strtol(buffer, &buffer, 10); + + if (person->time == 0) return GIT_EOBJCORRUPTED; - return (buffer < buffer_end) ? 0 : -1; + *buffer_out = (line_end + 1); + return 0; } -int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header) +int git_commit__parse_oid(git_oid *oid, char **buffer_out, + const char *buffer_end, const char *header) { const size_t sha_len = GIT_OID_HEXSZ; const size_t header_len = strlen(header); @@ -183,28 +244,33 @@ int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_en return 0; } -int git_commit__parse_buffer(git_commit *commit, void *data, size_t len) +int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid oid; - - if (commit->parsed) - return 0; + git_commit_person person; if (git_commit__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0) return GIT_EOBJCORRUPTED; - commit->tree = git_tree_lookup(commit->object.pool, &oid); + if (parse_flags & GIT_COMMIT_TREE) + commit->tree = git_tree_lookup(commit->object.pool, &oid); /* * TODO: commit grafts! */ + if (parse_flags & GIT_COMMIT_PARENTS) + git_commit_list_clear(&commit->parents, 0); + while (git_commit__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) { git_commit *parent; + if ((parse_flags & GIT_COMMIT_PARENTS) == 0) + continue; + if ((parent = git_commit_lookup(commit->object.pool, &oid)) == NULL) return GIT_ENOTFOUND; @@ -216,14 +282,117 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len) return GIT_ENOMEM; } - if (git_commit__parse_time(&commit->commit_time, buffer, buffer_end) < 0) + if (git_commit__parse_person(&person, &buffer, buffer_end, "author ") < 0) return GIT_EOBJCORRUPTED; - commit->parsed = 1; + if (parse_flags & GIT_COMMIT_AUTHOR) { + if (commit->author) + free(commit->author); + + commit->author = git__malloc(sizeof(git_commit_person)); + memcpy(commit->author, &person, sizeof(git_commit_person)); + } + + if (git_commit__parse_person(&person, &buffer, buffer_end, "committer ") < 0) + return GIT_EOBJCORRUPTED; + + if (parse_flags & GIT_COMMIT_TIME) + commit->commit_time = person.time; + + if (parse_flags & GIT_COMMIT_COMMITTER) { + if (commit->committer) + free(commit->committer); + + commit->committer = git__malloc(sizeof(git_commit_person)); + memcpy(commit->committer, &person, sizeof(git_commit_person)); + } + + /* parse commit message */ + while (buffer <= buffer_end && *buffer == '\n') + buffer++; + + if (buffer < buffer_end) + { + if (parse_flags & GIT_COMMIT_MESSAGE) { + size_t message_len = buffer_end - buffer; + + commit->message = git__malloc(message_len + 1); + memcpy(commit->message, buffer, message_len); + commit->message[message_len] = 0; + } + + if (parse_flags & GIT_COMMIT_MESSAGE_SHORT) { + char *line_end; + size_t message_len; + + line_end = memchr(buffer, '\n', buffer_end - buffer); + message_len = line_end - buffer; + + commit->message_short = git__malloc(message_len + 1); + memcpy(commit->message_short, buffer, message_len); + commit->message_short[message_len] = 0; + } + } return 0; } +const git_tree *git_commit_tree(git_commit *commit) +{ + if (commit->tree) + return commit->tree; + + git_commit__parse(commit, GIT_COMMIT_TREE, 0); + return commit->tree; +} + +const git_commit_person *git_commit_author(git_commit *commit) +{ + if (commit->author) + return commit->author; + + git_commit__parse(commit, GIT_COMMIT_AUTHOR, 0); + return commit->author; +} + +const git_commit_person *git_commit_committer(git_commit *commit) +{ + if (commit->committer) + return commit->committer; + + git_commit__parse(commit, GIT_COMMIT_COMMITTER, 0); + return commit->committer; +} + +time_t git_commit_time(git_commit *commit) +{ + if (commit->commit_time) + return commit->commit_time; + + git_commit__parse(commit, GIT_COMMIT_TIME, 0); + return commit->commit_time; +} + +const char *git_commit_message(git_commit *commit) +{ + if (commit->message) + return commit->message; + + git_commit__parse(commit, GIT_COMMIT_MESSAGE, 0); + return commit->message; +} + +const char *git_commit_message_short(git_commit *commit) +{ + if (commit->message_short) + return commit->message_short; + + git_commit__parse(commit, GIT_COMMIT_MESSAGE_SHORT, 0); + return commit->message_short; +} + + + int git_commit_list_push_back(git_commit_list *list, git_commit *commit) { git_commit_node *node = NULL; diff --git a/src/commit.h b/src/commit.h index 524570f2c..36fd65cf2 100644 --- a/src/commit.h +++ b/src/commit.h @@ -23,31 +23,46 @@ struct git_commit_list { typedef struct git_commit_list git_commit_list; typedef struct git_commit_node git_commit_node; +#define GIT_COMMIT_TREE (1 << 1) +#define GIT_COMMIT_PARENTS (1 << 2) +#define GIT_COMMIT_AUTHOR (1 << 3) +#define GIT_COMMIT_COMMITTER (1 << 4) +#define GIT_COMMIT_TIME (1 << 5) +#define GIT_COMMIT_MESSAGE (1 << 6) +#define GIT_COMMIT_MESSAGE_SHORT (1 << 7) +#define GIT_COMMIT_FOOTERS (1 << 8) struct git_commit { git_revpool_object object; + git_obj odb_object; time_t commit_time; git_commit_list parents; git_tree *tree; + git_commit_person *author; + git_commit_person *committer; + + char *message; + char *message_short; unsigned short in_degree; - unsigned parsed:1, + unsigned basic_parse:1, + odb_open:1, seen:1, uninteresting:1, topo_delay:1, - flags:26; + flags:25; }; void git_commit__free(git_commit *c); +int git_commit__parse(git_commit *commit, unsigned int flags, int close_odb); +int git_commit__parse_basic(git_commit *commit); int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); -int git_commit__parse_buffer(git_commit *commit, void *data, size_t len); -int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end); +int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags); +int git_commit__parse_person(git_commit_person *person, char **buffer_out, const char *buffer_end, const char *header); void git_commit__mark_uninteresting(git_commit *commit); -int git_commit_parse_existing(git_commit *commit); - int git_commit_list_push_back(git_commit_list *list, git_commit *commit); int git_commit_list_push_front(git_commit_list *list, git_commit *commit); diff --git a/src/git/commit.h b/src/git/commit.h index 0ccf3c246..6d34f01ce 100644 --- a/src/git/commit.h +++ b/src/git/commit.h @@ -3,6 +3,7 @@ #include "common.h" #include "oid.h" +#include "tree.h" /** * @file git/commit.h @@ -16,6 +17,13 @@ GIT_BEGIN_DECL /** Parsed representation of a commit object. */ typedef struct git_commit git_commit; +/** Parsed representation of an author/committer of a commit */ +typedef struct git_commit_person { + char name[64]; /**< Full name */ + char email[64]; /**< Email address */ + time_t time; /**< Time when this person commited the change */ +} git_commit_person; + /** * Locate a reference to a commit without loading it. * The generated commit object is owned by the revision @@ -45,11 +53,53 @@ GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id); /** * Get the id of a commit. - * @param commit a previously parsed commit. + * @param commit a previously loaded commit. * @return object identity for the commit. */ GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit); +/** + * Get the short (one line) message of a commit. + * @param commit a previously loaded commit. + * @return the short message of a commit + */ +GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit); + +/** + * Get the full message of a commit. + * @param commit a previously loaded commit. + * @return the message of a commit + */ +GIT_EXTERN(const char *) git_commit_message(git_commit *commit); + +/** + * Get the commit time (i.e. committer time) of a commit. + * @param commit a previously loaded commit. + * @return the time of a commit + */ +GIT_EXTERN(time_t) git_commit_time(git_commit *commit); + +/** + * Get the committer of a commit. + * @param commit a previously loaded commit. + * @return the committer of a commit + */ +GIT_EXTERN(const git_commit_person *) git_commit_committer(git_commit *commit); + +/** + * Get the author of a commit. + * @param commit a previously loaded commit. + * @return the author of a commit + */ +GIT_EXTERN(const git_commit_person *) git_commit_author(git_commit *commit); + +/** + * Get the tree pointed to by a commit. + * @param commit a previously loaded commit. + * @return the tree of a commit + */ +GIT_EXTERN(const git_tree *) git_commit_tree(git_commit *commit); + /** @} */ GIT_END_DECL #endif diff --git a/src/revwalk.c b/src/revwalk.c index 422ef9df8..d4627ae2e 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -92,8 +92,9 @@ int gitrp_push(git_revpool *pool, git_commit *commit) if (commit->object.pool != pool || pool->walking) return GIT_ERROR; - if (!commit->parsed) { - int error = git_commit_parse_existing(commit); + if (!commit->basic_parse) { + int error = git_commit__parse_basic(commit); + if (error < 0) return error; } @@ -129,8 +130,8 @@ int gitrp__enroot(git_revpool *pool, git_commit *commit) if (commit->seen) return 0; - if (commit->parsed == 0) { - error = git_commit_parse_existing(commit); + if (!commit->basic_parse) { + error = git_commit__parse_basic(commit); if (error < 0) return error; } diff --git a/tests/t0401-parse.c b/tests/t0401-parse.c index d01f7573a..3c6a4c09f 100644 --- a/tests/t0401-parse.c +++ b/tests/t0401-parse.c @@ -7,13 +7,13 @@ static char *test_commits_broken[] = { - /* empty commit */ +/* empty commit */ "", - /* random garbage */ +/* random garbage */ "asd97sa9du902e9a0jdsuusad09as9du098709aweu8987sd\n", - /* broken endlines 1 */ +/* broken endlines 1 */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\r\n\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\r\n\ author Vicent Marti 1273848544 +0200\r\n\ @@ -21,7 +21,7 @@ committer Vicent Marti 1273848544 +0200\r\n\ \r\n\ a test commit with broken endlines\r\n", - /* broken endlines 2 */ +/* broken endlines 2 */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\ author Vicent Marti 1273848544 +0200\ @@ -29,7 +29,7 @@ committer Vicent Marti 1273848544 +0200\ \ another test commit with broken endlines", - /* starting endlines */ +/* starting endlines */ "\ntree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\ author Vicent Marti 1273848544 +0200\n\ @@ -37,53 +37,40 @@ committer Vicent Marti 1273848544 +0200\n\ \n\ a test commit with a starting endline\n", - /* corrupted commit 1 */ +/* corrupted commit 1 */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent 05452d6349abcd67aa396df", - /* corrupted commit 2 */ +/* corrupted commit 2 */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent ", - /* corrupted commit 3 */ +/* corrupted commit 3 */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent ", - /* corrupted commit 4 */ +/* corrupted commit 4 */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ par", - /* - * FIXME: duplicated parents? - * It this supposed to pass? - */ -/* -"tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ -parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\ -parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\ -author Vicent Marti 1273848544 +0200\n\ -committer Vicent Marti 1273848544 +0200\n\ -\n\ -duplicated parent", -*/ }; static char *test_commits_working[] = { - /* simple commit with no message */ +/* simple commit with no message */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n", - /* simple commit, no parent */ +/* simple commit, no parent */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n\ a simple commit which works\n", - /* simple commit, 1 parents */ +/* simple commit, 1 parents */ "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\ author Vicent Marti 1273848544 +0200\n\ @@ -94,81 +81,179 @@ a simple commit which works\n", BEGIN_TEST(parse_oid_test) - git_oid oid; + git_oid oid; #define TEST_OID_PASS(string, header) { \ - char *ptr = string;\ - char *ptr_original = ptr;\ - size_t len = strlen(ptr);\ - must_pass(git_commit__parse_oid(&oid, &ptr, ptr + len, header));\ - must_be_true(ptr == ptr_original + len);\ + char *ptr = string;\ + char *ptr_original = ptr;\ + size_t len = strlen(ptr);\ + must_pass(git_commit__parse_oid(&oid, &ptr, ptr + len, header));\ + must_be_true(ptr == ptr_original + len);\ } #define TEST_OID_FAIL(string, header) { \ - char *ptr = string;\ - size_t len = strlen(ptr);\ - must_fail(git_commit__parse_oid(&oid, &ptr, ptr + len, header));\ + char *ptr = string;\ + size_t len = strlen(ptr);\ + must_fail(git_commit__parse_oid(&oid, &ptr, ptr + len, header));\ } - TEST_OID_PASS("parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "parent "); - TEST_OID_PASS("tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree "); - TEST_OID_PASS("random_heading 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "random_heading "); - TEST_OID_PASS("stuck_heading05452d6349abcd67aa396dfb28660d765d8b2a36\n", "stuck_heading"); - TEST_OID_PASS("tree 5F4BEFFC0759261D015AA63A3A85613FF2F235DE\n", "tree "); - TEST_OID_PASS("tree 1A669B8AB81B5EB7D9DB69562D34952A38A9B504\n", "tree "); - TEST_OID_PASS("tree 5B20DCC6110FCC75D31C6CEDEBD7F43ECA65B503\n", "tree "); - TEST_OID_PASS("tree 173E7BF00EA5C33447E99E6C1255954A13026BE4\n", "tree "); + TEST_OID_PASS("parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "parent "); + TEST_OID_PASS("tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree "); + TEST_OID_PASS("random_heading 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "random_heading "); + TEST_OID_PASS("stuck_heading05452d6349abcd67aa396dfb28660d765d8b2a36\n", "stuck_heading"); + TEST_OID_PASS("tree 5F4BEFFC0759261D015AA63A3A85613FF2F235DE\n", "tree "); + TEST_OID_PASS("tree 1A669B8AB81B5EB7D9DB69562D34952A38A9B504\n", "tree "); + TEST_OID_PASS("tree 5B20DCC6110FCC75D31C6CEDEBD7F43ECA65B503\n", "tree "); + TEST_OID_PASS("tree 173E7BF00EA5C33447E99E6C1255954A13026BE4\n", "tree "); - TEST_OID_FAIL("parent 05452d6349abcd67aa396dfb28660d765d8b2a36", "parent "); - TEST_OID_FAIL("05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree "); - TEST_OID_FAIL("parent05452d6349abcd67aa396dfb28660d765d8b2a6a\n", "parent "); - TEST_OID_FAIL("parent 05452d6349abcd67aa396dfb280d765d8b2a6\n", "parent "); - TEST_OID_FAIL("tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree "); - TEST_OID_FAIL("parent 0545xd6349abcd67aa396dfb28660d765d8b2a36\n", "parent "); - TEST_OID_FAIL("parent 0545xd6349abcd67aa396dfb28660d765d8b2a36FF\n", "parent "); - TEST_OID_FAIL("", "tree "); - TEST_OID_FAIL("", ""); + TEST_OID_FAIL("parent 05452d6349abcd67aa396dfb28660d765d8b2a36", "parent "); + TEST_OID_FAIL("05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree "); + TEST_OID_FAIL("parent05452d6349abcd67aa396dfb28660d765d8b2a6a\n", "parent "); + TEST_OID_FAIL("parent 05452d6349abcd67aa396dfb280d765d8b2a6\n", "parent "); + TEST_OID_FAIL("tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree "); + TEST_OID_FAIL("parent 0545xd6349abcd67aa396dfb28660d765d8b2a36\n", "parent "); + TEST_OID_FAIL("parent 0545xd6349abcd67aa396dfb28660d765d8b2a36FF\n", "parent "); + TEST_OID_FAIL("", "tree "); + TEST_OID_FAIL("", ""); #undef TEST_OID_PASS #undef TEST_OID_FAIL END_TEST -BEGIN_TEST(parse_buffer_test) - const int broken_commit_count = sizeof(test_commits_broken) / sizeof(*test_commits_broken); - const int working_commit_count = sizeof(test_commits_working) / sizeof(*test_commits_working); - int i; +BEGIN_TEST(parse_person_test) - git_revpool *pool = gitrp_alloc(NULL); +#define TEST_PERSON_PASS(_string, _header, _name, _email, _time) { \ + char *ptr = _string; \ + size_t len = strlen(_string);\ + git_commit_person person; \ + must_pass(git_commit__parse_person(&person, &ptr, ptr + len, _header));\ + must_be_true(strncmp(_name, person.name, 63) == 0);\ + must_be_true(strncmp(_email, person.email, 63) == 0);\ + must_be_true(_time == person.time);\ +} - for (i = 0; i < broken_commit_count; ++i) { - git_commit commit; - memset(&commit, 0x0, sizeof(git_commit)); - commit.object.pool = pool; +#define TEST_PERSON_FAIL(_string, _header) { \ + char *ptr = _string; \ + size_t len = strlen(_string);\ + git_commit_person person; \ + must_fail(git_commit__parse_person(&person, &ptr, ptr + len, _header));\ +} - must_fail(git_commit__parse_buffer( - &commit, - test_commits_broken[i], - strlen(test_commits_broken[i])) - ); + TEST_PERSON_PASS( + "author Vicent Marti 12345 \n", + "author ", + "Vicent Marti", + "tanoku@gmail.com", + 12345); - git_commit_list_clear(&commit.parents, 0); - } + TEST_PERSON_PASS( + "author Vicent Marti <> 12345 \n", + "author ", + "Vicent Marti", + "", + 12345); - for (i = 0; i < working_commit_count; ++i) { - git_commit commit; - memset(&commit, 0x0, sizeof(git_commit)); - commit.object.pool = pool; + TEST_PERSON_PASS( + "author Vicent Marti 231301 +2020\n", + "author ", + "Vicent Marti", + "tanoku@gmail.com", + 231301); - must_pass(git_commit__parse_buffer( - &commit, - test_commits_working[i], - strlen(test_commits_working[i])) - ); + TEST_PERSON_PASS( + "author Vicent Marti with an outrageously long name \ + which will probably overflow the buffer 12345 \n", + "author ", + "Vicent Marti with an outrageously long name \ + which will probably overflow the buffer", + "tanoku@gmail.com", + 12345); - git_commit_list_clear(&commit.parents, 0); - } + TEST_PERSON_PASS( + "author Vicent Marti 12345 \n", + "author ", + "Vicent Marti", + "tanokuwithaveryveryverylongemail\ + whichwillprobablyvoverflowtheemailbuffer@gmail.com", + 12345); - gitrp_free(pool); + TEST_PERSON_FAIL( + "author Vicent Marti 12345 \n", + "author "); + + TEST_PERSON_FAIL( + "author Vicent Marti 12345 \n", + "committer "); + + TEST_PERSON_FAIL( + "author Vicent Marti 12345 \n", + "author "); + + TEST_PERSON_FAIL( + "author Vicent Marti notime \n", + "author "); + + TEST_PERSON_FAIL( + "author Vicent Marti \n", + "author "); + + TEST_PERSON_FAIL( + "author ", + "author "); + +#undef TEST_PERSON_PASS +#undef TESt_PERSON_FAIL + +END_TEST + +BEGIN_TEST(parse_buffer_test) + const int broken_commit_count = sizeof(test_commits_broken) / sizeof(*test_commits_broken); + const int working_commit_count = sizeof(test_commits_working) / sizeof(*test_commits_working); + + const unsigned int default_flags = 0xFF; /* parse everything */ + + int i; + + git_revpool *pool = gitrp_alloc(NULL); + + for (i = 0; i < broken_commit_count; ++i) { + git_commit *commit; + commit = git__malloc(sizeof(git_commit)); + memset(commit, 0x0, sizeof(git_commit)); + commit->object.pool = pool; + + must_fail(git_commit__parse_buffer( + commit, + test_commits_broken[i], + strlen(test_commits_broken[i]), + default_flags) + ); + + git_commit__free(commit); + } + + for (i = 0; i < working_commit_count; ++i) { + git_commit *commit; + commit = git__malloc(sizeof(git_commit)); + memset(commit, 0x0, sizeof(git_commit)); + commit->object.pool = pool; + + must_pass(git_commit__parse_buffer( + commit, + test_commits_working[i], + strlen(test_commits_working[i]), + default_flags) + ); + + git_commit__free(commit); + } + + gitrp_free(pool); END_TEST diff --git a/tests/t0402-details.c b/tests/t0402-details.c new file mode 100644 index 000000000..15c883bae --- /dev/null +++ b/tests/t0402-details.c @@ -0,0 +1,61 @@ +#include "test_lib.h" +#include "test_helpers.h" +#include "commit.h" + +#include +#include +#include + +static const char *odb_dir = "../t0501-objects"; +static const char *commit_ids[] = { + "a4a7dce85cf63874e984719f4fdd239f5145052f", /* 0 */ + "9fd738e8f7967c078dceed8190330fc8648ee56a", /* 1 */ + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", /* 2 */ + "c47800c7266a2be04c571c04d5a6614691ea99bd", /* 3 */ + "8496071c1b46c854b31185ea97743be6a8774479", /* 4 */ + "5b5b025afb0b4c913b4c338a42934a3863bf3644", /* 5 */ +}; + +BEGIN_TEST(query_details_test) + const size_t commit_count = sizeof(commit_ids) / sizeof(const char *); + + unsigned int i; + git_odb *db; + git_revpool *pool; + + must_pass(git_odb_open(&db, odb_dir)); + + pool = gitrp_alloc(db); + must_be_true(pool != NULL); + + for (i = 0; i < commit_count; ++i) { + git_oid id; + git_commit *commit; + + const git_commit_person *author, *committer; + const char *message, *message_short; + time_t commit_time; + + git_oid_mkstr(&id, commit_ids[i]); + + commit = git_commit_parse(pool, &id); + must_be_true(commit != NULL); + + message = git_commit_message(commit); + message_short = git_commit_message_short(commit); + author = git_commit_author(commit); + committer = git_commit_committer(commit); + commit_time = git_commit_time(commit); + + must_be_true(strcmp(author->name, "Scott Chacon") == 0); + must_be_true(strcmp(author->email, "schacon@gmail.com") == 0); + must_be_true(strcmp(committer->name, "Scott Chacon") == 0); + must_be_true(strcmp(committer->email, "schacon@gmail.com") == 0); + must_be_true(strchr(message, '\n') != NULL); + must_be_true(strchr(message_short, '\n') == NULL); + must_be_true(commit_time > 0); + } + + gitrp_free(pool); + git_odb_close(db); +END_TEST