Merge pull request #413 from MichaelMure/repo-more-tests

Michael Muré created

repo: more tests

Change summary

bug/bug.go                             |   2 
identity/identity.go                   |   2 
misc/random_bugs/create_random_bugs.go |   3 
repository/git.go                      |   4 
repository/mock_repo.go                |  48 ++++++++-
repository/repo.go                     |  18 +-
repository/repo_testing.go             | 130 ++++++++++++++++++++++++++-
7 files changed, 180 insertions(+), 27 deletions(-)

Detailed changes

bug/bug.go 🔗

@@ -138,7 +138,7 @@ func readBug(repo repository.ClockedRepo, ref string) (*Bug, error) {
 
 	// Load each OperationPack
 	for _, hash := range hashes {
-		entries, err := repo.ListEntries(hash)
+		entries, err := repo.ReadTree(hash)
 		if err != nil {
 			return nil, errors.Wrap(err, "can't list git tree entries")
 		}

identity/identity.go 🔗

@@ -118,7 +118,7 @@ func read(repo repository.Repo, ref string) (*Identity, error) {
 	}
 
 	for _, hash := range hashes {
-		entries, err := repo.ListEntries(hash)
+		entries, err := repo.ReadTree(hash)
 		if err != nil {
 			return nil, errors.Wrap(err, "can't list git tree entries")
 		}

misc/random_bugs/create_random_bugs.go 🔗

@@ -5,10 +5,11 @@ import (
 	"strings"
 	"time"
 
+	"github.com/icrowley/fake"
+
 	"github.com/MichaelMure/git-bug/bug"
 	"github.com/MichaelMure/git-bug/identity"
 	"github.com/MichaelMure/git-bug/repository"
-	"github.com/icrowley/fake"
 )
 
 type opsGenerator func(bug.Interface, identity.Interface, int64)

repository/git.go 🔗

@@ -337,8 +337,8 @@ func (repo *GitRepo) ListCommits(ref string) ([]git.Hash, error) {
 
 }
 
-// ListEntries will return the list of entries in a Git tree
-func (repo *GitRepo) ListEntries(hash git.Hash) ([]TreeEntry, error) {
+// ReadTree will return the list of entries in a Git tree
+func (repo *GitRepo) ReadTree(hash git.Hash) ([]TreeEntry, error) {
 	stdout, err := repo.runGitCommand("ls-tree", string(hash))
 
 	if err != nil {

repository/mock_repo.go 🔗

@@ -3,6 +3,7 @@ package repository
 import (
 	"crypto/sha1"
 	"fmt"
+	"strings"
 
 	"github.com/MichaelMure/git-bug/util/git"
 	"github.com/MichaelMure/git-bug/util/lamport"
@@ -151,12 +152,12 @@ func (r *mockRepoForTest) CopyRef(source string, dest string) error {
 }
 
 func (r *mockRepoForTest) ListRefs(refspec string) ([]string, error) {
-	keys := make([]string, len(r.refs))
+	var keys []string
 
-	i := 0
 	for k := range r.refs {
-		keys[i] = k
-		i++
+		if strings.HasPrefix(k, refspec) {
+			keys = append(keys, k)
+		}
 	}
 
 	return keys, nil
@@ -181,7 +182,7 @@ func (r *mockRepoForTest) ListCommits(ref string) ([]git.Hash, error) {
 	return hashes, nil
 }
 
-func (r *mockRepoForTest) ListEntries(hash git.Hash) ([]TreeEntry, error) {
+func (r *mockRepoForTest) ReadTree(hash git.Hash) ([]TreeEntry, error) {
 	var data string
 
 	data, ok := r.trees[hash]
@@ -205,11 +206,44 @@ func (r *mockRepoForTest) ListEntries(hash git.Hash) ([]TreeEntry, error) {
 }
 
 func (r *mockRepoForTest) FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error) {
-	panic("implement me")
+	ancestor1 := []git.Hash{hash1}
+
+	for hash1 != "" {
+		c, ok := r.commits[hash1]
+		if !ok {
+			return "", fmt.Errorf("unknown commit %v", hash1)
+		}
+		ancestor1 = append(ancestor1, c.parent)
+		hash1 = c.parent
+	}
+
+	for {
+		for _, ancestor := range ancestor1 {
+			if ancestor == hash2 {
+				return ancestor, nil
+			}
+		}
+
+		c, ok := r.commits[hash2]
+		if !ok {
+			return "", fmt.Errorf("unknown commit %v", hash1)
+		}
+
+		if c.parent == "" {
+			return "", fmt.Errorf("no ancestor found")
+		}
+
+		hash2 = c.parent
+	}
 }
 
 func (r *mockRepoForTest) GetTreeHash(commit git.Hash) (git.Hash, error) {
-	panic("implement me")
+	c, ok := r.commits[commit]
+	if !ok {
+		return "", fmt.Errorf("unknown commit")
+	}
+
+	return c.treeHash, nil
 }
 
 func (r *mockRepoForTest) GetOrCreateClock(name string) (lamport.Clock, error) {

repository/repo.go 🔗

@@ -66,12 +66,21 @@ type Repo interface {
 	// StoreTree will store a mapping key-->Hash as a Git tree
 	StoreTree(mapping []TreeEntry) (git.Hash, error)
 
+	// ReadTree will return the list of entries in a Git tree
+	ReadTree(hash git.Hash) ([]TreeEntry, error)
+
 	// StoreCommit will store a Git commit with the given Git tree
 	StoreCommit(treeHash git.Hash) (git.Hash, error)
 
 	// StoreCommit will store a Git commit with the given Git tree
 	StoreCommitWithParent(treeHash git.Hash, parent git.Hash) (git.Hash, error)
 
+	// GetTreeHash return the git tree hash referenced in a commit
+	GetTreeHash(commit git.Hash) (git.Hash, error)
+
+	// FindCommonAncestor will return the last common ancestor of two chain of commit
+	FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error)
+
 	// UpdateRef will create or update a Git reference
 	UpdateRef(ref string, hash git.Hash) error
 
@@ -86,15 +95,6 @@ type Repo interface {
 
 	// ListCommits will return the list of tree hashes of a ref, in chronological order
 	ListCommits(ref string) ([]git.Hash, error)
-
-	// ListEntries will return the list of entries in a Git tree
-	ListEntries(hash git.Hash) ([]TreeEntry, error)
-
-	// FindCommonAncestor will return the last common ancestor of two chain of commit
-	FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error)
-
-	// GetTreeHash return the git tree hash referenced in a commit
-	GetTreeHash(commit git.Hash) (git.Hash, error)
 }
 
 // ClockedRepo is a Repo that also has Lamport clocks

repository/repo_testing.go 🔗

@@ -2,12 +2,15 @@ package repository
 
 import (
 	"log"
+	"math/rand"
 	"os"
 	"strings"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+
+	"github.com/MichaelMure/git-bug/util/git"
 )
 
 func CleanupTestRepos(repos ...Repo) {
@@ -46,19 +49,125 @@ type RepoCleaner func(repos ...Repo)
 
 // Test suite for a Repo implementation
 func RepoTest(t *testing.T, creator RepoCreator, cleaner RepoCleaner) {
-	t.Run("Read/Write data", func(t *testing.T) {
+	t.Run("Blob-Tree-Commit-Ref", func(t *testing.T) {
 		repo := creator(false)
 		defer cleaner(repo)
 
-		data := []byte("hello")
+		// Blob
+
+		data := randomData()
+
+		blobHash1, err := repo.StoreData(data)
+		require.NoError(t, err)
+		assert.True(t, blobHash1.IsValid())
+
+		blob1Read, err := repo.ReadData(blobHash1)
+		require.NoError(t, err)
+		assert.Equal(t, data, blob1Read)
+
+		// Tree
+
+		blobHash2, err := repo.StoreData(randomData())
+		require.NoError(t, err)
+		blobHash3, err := repo.StoreData(randomData())
+		require.NoError(t, err)
+
+		tree1 := []TreeEntry{
+			{
+				ObjectType: Blob,
+				Hash:       blobHash1,
+				Name:       "blob1",
+			},
+			{
+				ObjectType: Blob,
+				Hash:       blobHash2,
+				Name:       "blob2",
+			},
+		}
+
+		treeHash1, err := repo.StoreTree(tree1)
+		require.NoError(t, err)
+		assert.True(t, treeHash1.IsValid())
+
+		tree1Read, err := repo.ReadTree(treeHash1)
+		require.NoError(t, err)
+		assert.ElementsMatch(t, tree1, tree1Read)
+
+		tree2 := []TreeEntry{
+			{
+				ObjectType: Tree,
+				Hash:       treeHash1,
+				Name:       "tree1",
+			},
+			{
+				ObjectType: Blob,
+				Hash:       blobHash3,
+				Name:       "blob3",
+			},
+		}
+
+		treeHash2, err := repo.StoreTree(tree2)
+		require.NoError(t, err)
+		assert.True(t, treeHash2.IsValid())
+
+		tree2Read, err := repo.ReadTree(treeHash2)
+		require.NoError(t, err)
+		assert.ElementsMatch(t, tree2, tree2Read)
+
+		// Commit
+
+		commit1, err := repo.StoreCommit(treeHash1)
+		require.NoError(t, err)
+		assert.True(t, commit1.IsValid())
+
+		treeHash1Read, err := repo.GetTreeHash(commit1)
+		require.NoError(t, err)
+		assert.Equal(t, treeHash1, treeHash1Read)
+
+		commit2, err := repo.StoreCommitWithParent(treeHash2, commit1)
+		require.NoError(t, err)
+		assert.True(t, commit2.IsValid())
+
+		treeHash2Read, err := repo.GetTreeHash(commit2)
+		require.NoError(t, err)
+		assert.Equal(t, treeHash2, treeHash2Read)
+
+		// Ref
+
+		exist1, err := repo.RefExist("refs/bugs/ref1")
+		require.NoError(t, err)
+		assert.False(t, exist1)
+
+		err = repo.UpdateRef("refs/bugs/ref1", commit2)
+		require.NoError(t, err)
+
+		exist1, err = repo.RefExist("refs/bugs/ref1")
+		require.NoError(t, err)
+		assert.True(t, exist1)
 
-		h, err := repo.StoreData(data)
+		ls, err := repo.ListRefs("refs/bugs")
 		require.NoError(t, err)
-		assert.NotEmpty(t, h)
+		assert.Equal(t, []string{"refs/bugs/ref1"}, ls)
 
-		read, err := repo.ReadData(h)
+		err = repo.CopyRef("refs/bugs/ref1", "refs/bugs/ref2")
 		require.NoError(t, err)
-		assert.Equal(t, data, read)
+
+		ls, err = repo.ListRefs("refs/bugs")
+		require.NoError(t, err)
+		assert.Equal(t, []string{"refs/bugs/ref1", "refs/bugs/ref2"}, ls)
+
+		commits, err := repo.ListCommits("refs/bugs/ref2")
+		require.NoError(t, err)
+		assert.Equal(t, []git.Hash{commit1, commit2}, commits)
+
+		// Graph
+
+		commit3, err := repo.StoreCommitWithParent(treeHash1, commit1)
+		require.NoError(t, err)
+
+		ancestorHash, err := repo.FindCommonAncestor(commit2, commit3)
+		require.NoError(t, err)
+		assert.Equal(t, commit1, ancestorHash)
 	})
 
 	t.Run("Local config", func(t *testing.T) {
@@ -68,3 +177,12 @@ func RepoTest(t *testing.T, creator RepoCreator, cleaner RepoCleaner) {
 		testConfig(t, repo.LocalConfig())
 	})
 }
+
+func randomData() []byte {
+	var letterRunes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	b := make([]byte, 32)
+	for i := range b {
+		b[i] = letterRunes[rand.Intn(len(letterRunes))]
+	}
+	return b
+}