aboutsummaryrefslogtreecommitdiff
package commit_test

import (
	"bytes"
	"strings"
	"testing"

	"lindenii.org/go/furgit/internal/testgit"
	"lindenii.org/go/furgit/object/commit"
	"lindenii.org/go/furgit/object/id"
	"lindenii.org/go/furgit/object/typ"
)

func TestParse(t *testing.T) {
	t.Parallel()

	commitTreeOptions := func(message string) testgit.CommitTreeOptions {
		return testgit.CommitTreeOptions{
			Message: message,
			Author: testgit.Identity{
				Name:  "Test Author",
				Email: "author@example.org",
			},
			Committer: testgit.Identity{
				Name:  "Test Committer",
				Email: "committer@example.org",
			},
			AuthorDate:    "1234567890 -0730",
			CommitterDate: "1234567999 +0545",
		}
	}

	for _, objectFormat := range id.SupportedObjectFormats() {
		t.Run(objectFormat.String(), func(t *testing.T) {
			t.Parallel()

			repo, err := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: objectFormat})
			if err != nil {
				t.Fatalf("NewRepo: %v", err)
			}

			blobID, err := repo.HashObject(t, typ.TypeBlob, strings.NewReader("content\n"))
			if err != nil {
				t.Fatalf("HashObject: %v", err)
			}

			treeID, err := repo.MkTree(t, []testgit.TreeEntry{
				{Mode: "100644", Type: typ.TypeBlob, OID: blobID, Name: "file.txt"},
			})
			if err != nil {
				t.Fatalf("MkTree: %v", err)
			}

			rootID, err := repo.CommitTree(t, treeID, commitTreeOptions("root subject\n\nroot body"))
			if err != nil {
				t.Fatalf("CommitTree(root): %v", err)
			}

			childID, err := repo.CommitTree(t, treeID, commitTreeOptions("child subject\n\nchild body"), rootID)
			if err != nil {
				t.Fatalf("CommitTree(child): %v", err)
			}

			sideID, err := repo.CommitTree(t, treeID, commitTreeOptions("side subject\n\nside body"))
			if err != nil {
				t.Fatalf("CommitTree(side): %v", err)
			}

			mergeID, err := repo.CommitTree(t, treeID, commitTreeOptions("merge subject\n\nmerge body"), childID, sideID)
			if err != nil {
				t.Fatalf("CommitTree(merge): %v", err)
			}

			for _, tc := range []struct {
				name    string
				oid     id.ObjectID
				parents []id.ObjectID
				message []byte
			}{
				{
					name:    "root",
					oid:     rootID,
					message: []byte("root subject\n\nroot body\n"),
				},
				{
					name:    "child",
					oid:     childID,
					parents: []id.ObjectID{rootID},
					message: []byte("child subject\n\nchild body\n"),
				},
				{
					name:    "merge",
					oid:     mergeID,
					parents: []id.ObjectID{childID, sideID},
					message: []byte("merge subject\n\nmerge body\n"),
				},
			} {
				t.Run(tc.name, func(t *testing.T) {
					rawBody, err := repo.CatFile(t, typ.TypeCommit, tc.oid)
					if err != nil {
						t.Fatalf("CatFile: %v", err)
					}

					parsed, err := commit.Parse(rawBody, objectFormat)
					if err != nil {
						t.Fatalf("Parse: %v", err)
					}

					if parsed.Tree != treeID {
						t.Fatalf("tree id mismatch: got %s want %s", parsed.Tree, treeID)
					}

					if len(parsed.Parents) != len(tc.parents) {
						t.Fatalf("parent count = %d, want %d", len(parsed.Parents), len(tc.parents))
					}

					for i, parent := range tc.parents {
						if parsed.Parents[i] != parent {
							t.Fatalf("parent[%d] = %s, want %s", i, parsed.Parents[i], parent)
						}
					}

					if !bytes.Equal(parsed.Author.Name, []byte("Test Author")) {
						t.Fatalf("author name = %q, want %q", parsed.Author.Name, "Test Author")
					}

					if !bytes.Equal(parsed.Author.Email, []byte("author@example.org")) {
						t.Fatalf("author email = %q, want %q", parsed.Author.Email, "author@example.org")
					}

					if parsed.Author.WhenUnix != 1234567890 {
						t.Fatalf("author time = %d, want %d", parsed.Author.WhenUnix, int64(1234567890))
					}

					if parsed.Author.OffsetMinutes != -450 {
						t.Fatalf("author offset = %d, want %d", parsed.Author.OffsetMinutes, int32(-450))
					}

					if !bytes.Equal(parsed.Committer.Name, []byte("Test Committer")) {
						t.Fatalf("committer name = %q, want %q", parsed.Committer.Name, "Test Committer")
					}

					if !bytes.Equal(parsed.Committer.Email, []byte("committer@example.org")) {
						t.Fatalf("committer email = %q, want %q", parsed.Committer.Email, "committer@example.org")
					}

					if parsed.Committer.WhenUnix != 1234567999 {
						t.Fatalf("committer time = %d, want %d", parsed.Committer.WhenUnix, int64(1234567999))
					}

					if parsed.Committer.OffsetMinutes != 345 {
						t.Fatalf("committer offset = %d, want %d", parsed.Committer.OffsetMinutes, int32(345))
					}

					if !bytes.Equal(parsed.Message, tc.message) {
						t.Fatalf("message = %q, want %q", parsed.Message, tc.message)
					}
				})
			}
		})
	}
}