summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2010-07-07 14:56:05 +0200
committerVicent Marti <tanoku@gmail.com>2010-07-15 23:40:52 +0200
commit52f2390b4308fe51ecceecbc35a87bf6e74e9aa8 (patch)
tree15595ebcc29767ee05eb33adb216fc2e92af85f4
parent225fe21522a98075bdc18dae90ce459f797ac366 (diff)
downloadlibgit2-52f2390b4308fe51ecceecbc35a87bf6e74e9aa8.tar.gz
Add external API to access detailed commit attributes
The following new external methods have been added: GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit); GIT_EXTERN(const char *) git_commit_message(git_commit *commit); GIT_EXTERN(time_t) git_commit_time(git_commit *commit); GIT_EXTERN(const git_commit_person *) git_commit_committer(git_commit *commit); GIT_EXTERN(const git_commit_person *) git_commit_author(git_commit *commit); GIT_EXTERN(const git_tree *) git_commit_tree(git_commit *commit); A new structure, git_commit_person has been added to represent a commit's author or committer. The parsing of a commit has been split in two phases. When adding a commit to the revision pool: - the commit's ODB object is opened - its raw contents are parsed for commit TIME, PARENTS and TREE (the minimal amount of data required to traverse the pool) - the commit's ODB object is closed When querying for extended information on a commit: - the commit's ODB object is reopened - its raw contents are parsed for the requested information - the commit's ODB object remains open to handle additional queries New unit tests have been added for the new functionality: In t0401-parse: parse_person_test In t0402-details: query_details_test Signed-off-by: Vicent Marti <tanoku@gmail.com>
-rw-r--r--src/commit.c243
-rw-r--r--src/commit.h27
-rw-r--r--src/git/commit.h52
-rw-r--r--src/revwalk.c9
-rw-r--r--tests/t0401-parse.c243
-rw-r--r--tests/t0402-details.c61
6 files changed, 508 insertions, 127 deletions
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,30 +87,51 @@ 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)
- return 0;
+ if (!commit->odb_open) {
+ error = git_odb_read(&commit->odb_object, commit->object.pool->db, &commit->object.id);
+ if (error < 0)
+ return error;
- error = git_odb_read(&commit_obj, 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;
+ }
- if (commit_obj.type != GIT_OBJ_COMMIT) {
- error = GIT_EOBJTYPE;
- goto cleanup;
+ commit->odb_open = 1;
}
- error = git_commit__parse_buffer(commit, commit_obj.data, commit_obj.len);
+ 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;
+ }
-cleanup:
- git_obj_close(&commit_obj);
return error;
}
+int git_commit__parse_basic(git_commit *commit)
+{
+ int error;
+
+ if (commit->basic_parse)
+ return 0;
+
+ error = git_commit__parse(commit,
+ (GIT_COMMIT_TREE | GIT_COMMIT_PARENTS | GIT_COMMIT_TIME), 1);
+
+ if (error < 0)
+ return error;
+
+ commit->basic_parse = 1;
+ return 0;
+}
+
git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id)
{
git_commit *commit = NULL;
@@ -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++;
+
+ *email = 0;
+
+ while (buffer < line_end && *buffer != '>')
+ buffer++;
- if (*commit_time == 0)
+ 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 <tanoku@gmail.com> 1273848544 +0200\r\n\
@@ -21,7 +21,7 @@ committer Vicent Marti <tanoku@gmail.com> 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 <tanoku@gmail.com> 1273848544 +0200\
@@ -29,7 +29,7 @@ committer Vicent Marti <tanoku@gmail.com> 1273848544 +0200\
\
another test commit with broken endlines",
- /* starting endlines */
+/* starting endlines */
"\ntree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\
parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\
author Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\
@@ -37,53 +37,40 @@ committer Vicent Marti <tanoku@gmail.com> 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 <tanoku@gmail.com> 1273848544 +0200\n\
-committer Vicent Marti <tanoku@gmail.com> 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 <tanoku@gmail.com> 1273848544 +0200\n\
committer Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\
\n",
- /* simple commit, no parent */
+/* simple commit, no parent */
"tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\
author Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\
committer Vicent Marti <tanoku@gmail.com> 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 <tanoku@gmail.com> 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_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_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("", "");
#undef TEST_OID_PASS
#undef TEST_OID_FAIL
END_TEST
+BEGIN_TEST(parse_person_test)
+
+#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);\
+}
+
+#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));\
+}
+
+ TEST_PERSON_PASS(
+ "author Vicent Marti <tanoku@gmail.com> 12345 \n",
+ "author ",
+ "Vicent Marti",
+ "tanoku@gmail.com",
+ 12345);
+
+ TEST_PERSON_PASS(
+ "author Vicent Marti <> 12345 \n",
+ "author ",
+ "Vicent Marti",
+ "",
+ 12345);
+
+ TEST_PERSON_PASS(
+ "author Vicent Marti <tanoku@gmail.com> 231301 +2020\n",
+ "author ",
+ "Vicent Marti",
+ "tanoku@gmail.com",
+ 231301);
+
+ TEST_PERSON_PASS(
+ "author Vicent Marti with an outrageously long name \
+ which will probably overflow the buffer <tanoku@gmail.com> 12345 \n",
+ "author ",
+ "Vicent Marti with an outrageously long name \
+ which will probably overflow the buffer",
+ "tanoku@gmail.com",
+ 12345);
+
+ TEST_PERSON_PASS(
+ "author Vicent Marti <tanokuwithaveryveryverylongemail\
+ whichwillprobablyvoverflowtheemailbuffer@gmail.com> 12345 \n",
+ "author ",
+ "Vicent Marti",
+ "tanokuwithaveryveryverylongemail\
+ whichwillprobablyvoverflowtheemailbuffer@gmail.com",
+ 12345);
+
+ TEST_PERSON_FAIL(
+ "author Vicent Marti <tanoku@gmail.com> 12345 \n",
+ "author ");
+
+ TEST_PERSON_FAIL(
+ "author Vicent Marti <tanoku@gmail.com> 12345 \n",
+ "committer ");
+
+ TEST_PERSON_FAIL(
+ "author Vicent Marti 12345 \n",
+ "author ");
+
+ TEST_PERSON_FAIL(
+ "author Vicent Marti <broken@email 12345 \n",
+ "author ");
+
+ TEST_PERSON_FAIL(
+ "author Vicent Marti <tanoku@gmail.com> notime \n",
+ "author ");
+
+ TEST_PERSON_FAIL(
+ "author Vicent Marti <tanoku@gmail.com>\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);
- int i;
+ 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);
+ git_revpool *pool = gitrp_alloc(NULL);
- for (i = 0; i < broken_commit_count; ++i) {
- git_commit commit;
- memset(&commit, 0x0, sizeof(git_commit));
- commit.object.pool = pool;
+ 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]))
- );
+ must_fail(git_commit__parse_buffer(
+ commit,
+ test_commits_broken[i],
+ strlen(test_commits_broken[i]),
+ default_flags)
+ );
- git_commit_list_clear(&commit.parents, 0);
- }
+ git_commit__free(commit);
+ }
- for (i = 0; i < working_commit_count; ++i) {
- git_commit commit;
- memset(&commit, 0x0, sizeof(git_commit));
- commit.object.pool = pool;
+ 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]))
- );
+ must_pass(git_commit__parse_buffer(
+ commit,
+ test_commits_working[i],
+ strlen(test_commits_working[i]),
+ default_flags)
+ );
- git_commit_list_clear(&commit.parents, 0);
- }
+ git_commit__free(commit);
+ }
- gitrp_free(pool);
+ 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 <git/odb.h>
+#include <git/commit.h>
+#include <git/revwalk.h>
+
+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