Commit 5c3d5fb0182e8c5307dedf9af281fe367a30a16e

Vicent Martí 2011-10-13T12:16:07

Merge pull request #454 from brodie/parsing-fixes Improvements to tag, commit, and signature parsing

diff --git a/src/commit.c b/src/commit.c
index 0ee3854..ced457e 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -221,10 +221,10 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len)
 	}
 
 	/* parse commit message */
-	while (buffer < buffer_end && *buffer == '\n')
+	while (buffer < buffer_end - 1 && *buffer == '\n')
 		buffer++;
 
-	if (buffer < buffer_end) {
+	if (buffer <= buffer_end) {
 		commit->message = git__strndup(buffer, buffer_end - buffer);
 		if (!commit->message)
 			return GIT_ENOMEM;
diff --git a/src/signature.c b/src/signature.c
index ebb56d7..388e8d9 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -279,7 +279,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
 	if ((name_end = strchr(buffer, '<')) == NULL)
 		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Cannot find '<' in signature");
 
-	if ((email_end = strchr(buffer, '>')) == NULL)
+	if ((email_end = strchr(name_end, '>')) == NULL)
 		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Cannot find '>' in signature");
 
 	if (email_end < name_end)
diff --git a/src/tag.c b/src/tag.c
index fc9f8b5..ba75104 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -122,14 +122,15 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
 
 	buffer = search + 1;
 
-	tag->tagger = git__malloc(sizeof(git_signature));
-	if (tag->tagger == NULL)
-		return GIT_ENOMEM;
-
-	if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n')) != 0) {
-		free(tag->tag_name);
-		git_signature_free(tag->tagger);
-		return git__rethrow(error, "Failed to parse tag");
+	tag->tagger = NULL;
+	if (*buffer != '\n') {
+		tag->tagger = git__malloc(sizeof(git_signature));
+		if (tag->tagger == NULL)
+			return GIT_ENOMEM;
+
+		if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') != 0)) {
+			return git__rethrow(error, "Failed to parse tag");
+		}
 	}
 
 	if( *buffer != '\n' )
diff --git a/tests/resources/bad_tag.git/HEAD b/tests/resources/bad_tag.git/HEAD
new file mode 100644
index 0000000..cb089cd
--- /dev/null
+++ b/tests/resources/bad_tag.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/bad_tag.git/config b/tests/resources/bad_tag.git/config
new file mode 100644
index 0000000..2f89580
--- /dev/null
+++ b/tests/resources/bad_tag.git/config
@@ -0,0 +1,5 @@
+[core]
+        repositoryformatversion = 0
+        filemode = true
+        bare = true
+        logallrefupdates = true
diff --git a/tests/resources/bad_tag.git/objects/pack/pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.idx b/tests/resources/bad_tag.git/objects/pack/pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.idx
new file mode 100644
index 0000000..c404aa1
Binary files /dev/null and b/tests/resources/bad_tag.git/objects/pack/pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.idx differ
diff --git a/tests/resources/bad_tag.git/objects/pack/pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.pack b/tests/resources/bad_tag.git/objects/pack/pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.pack
new file mode 100644
index 0000000..90eac50
Binary files /dev/null and b/tests/resources/bad_tag.git/objects/pack/pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.pack differ
diff --git a/tests/resources/bad_tag.git/packed-refs b/tests/resources/bad_tag.git/packed-refs
new file mode 100644
index 0000000..f9fd2fd
--- /dev/null
+++ b/tests/resources/bad_tag.git/packed-refs
@@ -0,0 +1,3 @@
+# pack-refs with: peeled 
+eda9f45a2a98d4c17a09d681d88569fa4ea91755 refs/tags/e90810b
+^e90810b8df3e80c413d903f631643c716887138d
diff --git a/tests/resources/testrepo.git/objects/36/97d64be941a53d4ae8f6a271e4e3fa56b022cc b/tests/resources/testrepo.git/objects/36/97d64be941a53d4ae8f6a271e4e3fa56b022cc
new file mode 100644
index 0000000..9bb5b62
Binary files /dev/null and b/tests/resources/testrepo.git/objects/36/97d64be941a53d4ae8f6a271e4e3fa56b022cc differ
diff --git a/tests/resources/testrepo.git/objects/94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162 b/tests/resources/testrepo.git/objects/94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162
new file mode 100644
index 0000000..4cc3f4d
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162
@@ -0,0 +1 @@
+x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQ`6Kǥ^/-*|W3Py`%E\&g|0{Ӎ1X
\ No newline at end of file
diff --git a/tests/resources/testrepo.git/objects/a6/5fedf39aefe402d3bb6e24df4d4f5fe4547750 b/tests/resources/testrepo.git/objects/a6/5fedf39aefe402d3bb6e24df4d4f5fe4547750
new file mode 100644
index 0000000..29c8e82
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/a6/5fedf39aefe402d3bb6e24df4d4f5fe4547750
@@ -0,0 +1,3 @@
+xQ
+!@sBQ"	ٱ
r{<xƪ
+HlJSer!ZPTe*jUEo^2(XS€EDO<Yj$2s_&},}[~p7~<:	Zp?1_C0
\ No newline at end of file
diff --git a/tests/resources/testrepo.git/refs/heads/master b/tests/resources/testrepo.git/refs/heads/master
index 9536ad8..3d8f0a4 100644
--- a/tests/resources/testrepo.git/refs/heads/master
+++ b/tests/resources/testrepo.git/refs/heads/master
@@ -1 +1 @@
-be3563ae3f795b2b4353bcce3a527ad0a4f7f644
+a65fedf39aefe402d3bb6e24df4d4f5fe4547750
diff --git a/tests/t04-commit.c b/tests/t04-commit.c
index 88c7efd..3fb4d37 100644
--- a/tests/t04-commit.c
+++ b/tests/t04-commit.c
@@ -412,6 +412,14 @@ BEGIN_TEST(parse1, "parse the signature line in a commit")
 		1234567890,
 		0);
 
+	TEST_SIGNATURE_PASS(
+		"author A U Thor> <author@example.com> and others 1234567890\n",
+		"author ",
+		"A U Thor>",
+		"author@example.com",
+		1234567890,
+		0);
+
 	TEST_SIGNATURE_FAIL(
 		"committer Vicent Marti tanoku@gmail.com> 123456 -0100 \n",
 		"committer ");
@@ -560,6 +568,7 @@ static const char *commit_ids[] = {
 	"c47800c7266a2be04c571c04d5a6614691ea99bd", /* 3 */
 	"8496071c1b46c854b31185ea97743be6a8774479", /* 4 */
 	"5b5b025afb0b4c913b4c338a42934a3863bf3644", /* 5 */
+	"a65fedf39aefe402d3bb6e24df4d4f5fe4547750", /* 6 */
 };
 
 BEGIN_TEST(details0, "query the details on a parsed commit")
@@ -594,6 +603,7 @@ BEGIN_TEST(details0, "query the details on a parsed commit")
 		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(message != NULL);
 		must_be_true(strchr(message, '\n') != NULL);
 		must_be_true(commit_time > 0);
 		must_be_true(parents <= 2);
diff --git a/tests/t08-tag.c b/tests/t08-tag.c
index b0d4af8..216fb9d 100644
--- a/tests/t08-tag.c
+++ b/tests/t08-tag.c
@@ -30,6 +30,8 @@
 static const char *tag1_id = "b25fa35b38051e4ae45d4222e795f9df2e43f1d1";
 static const char *tag2_id = "7b4384978d2493e851f9cca7858815fac9b10980";
 static const char *tagged_commit = "e90810b8df3e80c413d903f631643c716887138d";
+static const char *bad_tag_id = "eda9f45a2a98d4c17a09d681d88569fa4ea91755";
+static const char *badly_tagged_commit = "e90810b8df3e80c413d903f631643c716887138d";
 
 BEGIN_TEST(read0, "read and parse a tag from the repository")
 	git_repository *repo;
@@ -106,6 +108,37 @@ BEGIN_TEST(read2, "list all tag names from the repository matching a specified p
 	git_repository_free(repo);
 END_TEST
 
+#define BAD_TAG_REPOSITORY_FOLDER TEST_RESOURCES "/bad_tag.git/"
+
+BEGIN_TEST(read3, "read and parse a tag without a tagger field")
+	git_repository *repo;
+	git_tag *bad_tag;
+	git_commit *commit;
+	git_oid id, id_commit;
+
+	must_pass(git_repository_open(&repo, BAD_TAG_REPOSITORY_FOLDER));
+
+	git_oid_fromstr(&id, bad_tag_id);
+	git_oid_fromstr(&id_commit, badly_tagged_commit);
+
+	must_pass(git_tag_lookup(&bad_tag, repo, &id));
+	must_be_true(bad_tag != NULL);
+
+	must_be_true(strcmp(git_tag_name(bad_tag), "e90810b") == 0);
+	must_be_true(git_oid_cmp(&id, git_tag_id(bad_tag)) == 0);
+	must_be_true(bad_tag->tagger == NULL);
+
+	must_pass(git_tag_target((git_object **)&commit, bad_tag));
+	must_be_true(commit != NULL);
+
+	must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0);
+
+	git_tag_close(bad_tag);
+	git_commit_close(commit);
+
+	git_repository_free(repo);
+END_TEST
+
 
 #define TAGGER_NAME "Vicent Marti"
 #define TAGGER_EMAIL "vicent@github.com"
@@ -304,6 +337,7 @@ BEGIN_SUITE(tag)
 	ADD_TEST(read0);
 	ADD_TEST(read1);
 	ADD_TEST(read2);
+	ADD_TEST(read3);
 
 	ADD_TEST(write0);
 	ADD_TEST(write2);
diff --git a/tests/t10-refs.c b/tests/t10-refs.c
index 6703415..1b3e0a3 100644
--- a/tests/t10-refs.c
+++ b/tests/t10-refs.c
@@ -70,7 +70,7 @@ END_TEST
 
 static const char *head_tracker_sym_ref_name = "head-tracker";
 static const char *current_head_target = "refs/heads/master";
-static const char *current_master_tip = "be3563ae3f795b2b4353bcce3a527ad0a4f7f644";
+static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
 
 BEGIN_TEST(readsym0, "lookup a symbolic reference")
 	git_repository *repo;