2017-05-15 21:59:55 +00:00
|
|
|
package odb
|
|
|
|
|
|
|
|
import (
|
2017-06-06 21:55:45 +00:00
|
|
|
"bufio"
|
2017-05-15 21:59:55 +00:00
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2017-06-21 03:06:57 +00:00
|
|
|
"sort"
|
2017-05-15 21:59:55 +00:00
|
|
|
"strconv"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestTreeReturnsCorrectObjectType(t *testing.T) {
|
|
|
|
assert.Equal(t, TreeObjectType, new(Tree).Type())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTreeEncoding(t *testing.T) {
|
|
|
|
tree := &Tree{
|
|
|
|
Entries: []*TreeEntry{
|
|
|
|
{
|
|
|
|
Name: "a.dat",
|
|
|
|
Oid: []byte("aaaaaaaaaaaaaaaaaaaa"),
|
|
|
|
Filemode: 0100644,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "subdir",
|
|
|
|
Oid: []byte("bbbbbbbbbbbbbbbbbbbb"),
|
|
|
|
Filemode: 040000,
|
|
|
|
},
|
2017-05-16 18:10:58 +00:00
|
|
|
{
|
|
|
|
Name: "submodule",
|
|
|
|
Oid: []byte("cccccccccccccccccccc"),
|
|
|
|
Filemode: 0160000,
|
|
|
|
},
|
2017-05-15 21:59:55 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
|
|
n, err := tree.Encode(buf)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.NotEqual(t, 0, n)
|
|
|
|
|
2017-06-21 02:42:40 +00:00
|
|
|
assertTreeEntry(t, buf, "a.dat", []byte("aaaaaaaaaaaaaaaaaaaa"), 0100644)
|
|
|
|
assertTreeEntry(t, buf, "subdir", []byte("bbbbbbbbbbbbbbbbbbbb"), 040000)
|
|
|
|
assertTreeEntry(t, buf, "submodule", []byte("cccccccccccccccccccc"), 0160000)
|
2017-05-15 21:59:55 +00:00
|
|
|
|
|
|
|
assert.Equal(t, 0, buf.Len())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTreeDecoding(t *testing.T) {
|
|
|
|
from := new(bytes.Buffer)
|
|
|
|
fmt.Fprintf(from, "%s %s\x00%s",
|
|
|
|
strconv.FormatInt(int64(0100644), 8),
|
|
|
|
"a.dat", []byte("aaaaaaaaaaaaaaaaaaaa"))
|
|
|
|
fmt.Fprintf(from, "%s %s\x00%s",
|
|
|
|
strconv.FormatInt(int64(040000), 8),
|
|
|
|
"subdir", []byte("bbbbbbbbbbbbbbbbbbbb"))
|
|
|
|
fmt.Fprintf(from, "%s %s\x00%s",
|
|
|
|
strconv.FormatInt(int64(0120000), 8),
|
|
|
|
"symlink", []byte("cccccccccccccccccccc"))
|
2017-05-16 18:10:58 +00:00
|
|
|
fmt.Fprintf(from, "%s %s\x00%s",
|
|
|
|
strconv.FormatInt(int64(0160000), 8),
|
|
|
|
"submodule", []byte("dddddddddddddddddddd"))
|
2017-05-15 21:59:55 +00:00
|
|
|
|
|
|
|
flen := from.Len()
|
|
|
|
|
|
|
|
tree := new(Tree)
|
|
|
|
n, err := tree.Decode(from, int64(flen))
|
|
|
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, flen, n)
|
|
|
|
|
2017-05-16 18:10:58 +00:00
|
|
|
require.Equal(t, 4, len(tree.Entries))
|
2017-05-15 21:59:55 +00:00
|
|
|
assert.Equal(t, &TreeEntry{
|
|
|
|
Name: "a.dat",
|
|
|
|
Oid: []byte("aaaaaaaaaaaaaaaaaaaa"),
|
|
|
|
Filemode: 0100644,
|
|
|
|
}, tree.Entries[0])
|
|
|
|
assert.Equal(t, &TreeEntry{
|
|
|
|
Name: "subdir",
|
|
|
|
Oid: []byte("bbbbbbbbbbbbbbbbbbbb"),
|
|
|
|
Filemode: 040000,
|
|
|
|
}, tree.Entries[1])
|
|
|
|
assert.Equal(t, &TreeEntry{
|
|
|
|
Name: "symlink",
|
|
|
|
Oid: []byte("cccccccccccccccccccc"),
|
|
|
|
Filemode: 0120000,
|
|
|
|
}, tree.Entries[2])
|
2017-05-16 18:10:58 +00:00
|
|
|
assert.Equal(t, &TreeEntry{
|
|
|
|
Name: "submodule",
|
|
|
|
Oid: []byte("dddddddddddddddddddd"),
|
|
|
|
Filemode: 0160000,
|
|
|
|
}, tree.Entries[3])
|
2017-05-15 21:59:55 +00:00
|
|
|
}
|
|
|
|
|
2017-06-06 22:08:29 +00:00
|
|
|
func TestTreeDecodingShaBoundary(t *testing.T) {
|
|
|
|
var from bytes.Buffer
|
|
|
|
|
|
|
|
fmt.Fprintf(&from, "%s %s\x00%s",
|
|
|
|
strconv.FormatInt(int64(0100644), 8),
|
|
|
|
"a.dat", []byte("aaaaaaaaaaaaaaaaaaaa"))
|
|
|
|
|
|
|
|
flen := from.Len()
|
|
|
|
|
|
|
|
tree := new(Tree)
|
|
|
|
n, err := tree.Decode(bufio.NewReaderSize(&from, flen-2), int64(flen))
|
|
|
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, flen, n)
|
|
|
|
|
|
|
|
require.Len(t, tree.Entries, 1)
|
|
|
|
assert.Equal(t, &TreeEntry{
|
|
|
|
Name: "a.dat",
|
|
|
|
Oid: []byte("aaaaaaaaaaaaaaaaaaaa"),
|
|
|
|
Filemode: 0100644,
|
|
|
|
}, tree.Entries[0])
|
|
|
|
}
|
|
|
|
|
2017-06-21 02:42:40 +00:00
|
|
|
type TreeEntryTypeTestCase struct {
|
|
|
|
Filemode int32
|
|
|
|
Expected ObjectType
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *TreeEntryTypeTestCase) Assert(t *testing.T) {
|
|
|
|
e := &TreeEntry{Filemode: c.Filemode}
|
|
|
|
|
|
|
|
got := e.Type()
|
|
|
|
|
|
|
|
assert.Equal(t, c.Expected, got,
|
|
|
|
"git/odb: expected type: %s, got: %s", c.Expected, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTreeEntryTypeResolution(t *testing.T) {
|
|
|
|
for desc, c := range map[string]*TreeEntryTypeTestCase{
|
|
|
|
"blob": {0100644, BlobObjectType},
|
|
|
|
"subtree": {040000, TreeObjectType},
|
|
|
|
"symlink": {0120000, BlobObjectType},
|
|
|
|
"commit": {0160000, CommitObjectType},
|
|
|
|
} {
|
|
|
|
t.Run(desc, c.Assert)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTreeEntryTypeResolutionUnknown(t *testing.T) {
|
|
|
|
e := &TreeEntry{Filemode: -1}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err == nil {
|
|
|
|
t.Fatal("git/odb: expected panic(), got none")
|
|
|
|
} else {
|
|
|
|
assert.Equal(t, "git/odb: unknown object type: -1", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
e.Type()
|
|
|
|
}
|
|
|
|
|
2017-06-21 03:06:57 +00:00
|
|
|
func TestSubtreeOrder(t *testing.T) {
|
|
|
|
// The below list (e1, e2, ..., e5) is entered in subtree order: that
|
|
|
|
// is, lexicographically byte-ordered as if blobs end in a '\0', and
|
|
|
|
// sub-trees end in a '/'.
|
|
|
|
//
|
|
|
|
// See:
|
|
|
|
// http://public-inbox.org/git/7vac6jfzem.fsf@assigned-by-dhcp.cox.net
|
2017-06-21 03:21:32 +00:00
|
|
|
e1 := &TreeEntry{Filemode: 0100644, Name: "a-"}
|
|
|
|
e2 := &TreeEntry{Filemode: 0100644, Name: "a-b"}
|
2017-06-21 03:06:57 +00:00
|
|
|
e3 := &TreeEntry{Filemode: 040000, Name: "a"}
|
2017-06-21 03:21:32 +00:00
|
|
|
e4 := &TreeEntry{Filemode: 0100644, Name: "a="}
|
|
|
|
e5 := &TreeEntry{Filemode: 0100644, Name: "a=b"}
|
2017-06-21 03:06:57 +00:00
|
|
|
|
|
|
|
// Create a set of entries in the wrong order:
|
|
|
|
entries := []*TreeEntry{e3, e4, e1, e5, e2}
|
|
|
|
|
|
|
|
sort.Sort(SubtreeOrder(entries))
|
|
|
|
|
|
|
|
// Assert that they are in the correct order after sorting in sub-tree
|
|
|
|
// order:
|
|
|
|
require.Len(t, entries, 5)
|
|
|
|
assert.Equal(t, "a-", entries[0].Name)
|
|
|
|
assert.Equal(t, "a-b", entries[1].Name)
|
|
|
|
assert.Equal(t, "a", entries[2].Name)
|
|
|
|
assert.Equal(t, "a=", entries[3].Name)
|
|
|
|
assert.Equal(t, "a=b", entries[4].Name)
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:16:38 +00:00
|
|
|
func TestSubtreeOrderReturnsEmptyForOutOfBounds(t *testing.T) {
|
|
|
|
o := SubtreeOrder([]*TreeEntry{{Name: "a"}})
|
|
|
|
|
|
|
|
assert.Equal(t, "", o.Name(len(o)+1))
|
|
|
|
}
|
|
|
|
|
2017-05-15 21:59:55 +00:00
|
|
|
func assertTreeEntry(t *testing.T, buf *bytes.Buffer,
|
2017-06-21 02:42:40 +00:00
|
|
|
name string, oid []byte, mode int32) {
|
2017-05-15 21:59:55 +00:00
|
|
|
|
|
|
|
fmode, err := buf.ReadBytes(' ')
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, []byte(strconv.FormatInt(int64(mode), 8)+" "), fmode)
|
|
|
|
|
|
|
|
fname, err := buf.ReadBytes('\x00')
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, []byte(name+"\x00"), fname)
|
|
|
|
|
|
|
|
var sha [20]byte
|
|
|
|
_, err = buf.Read(sha[:])
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, oid, sha[:])
|
|
|
|
}
|