github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/git/odb/tree_test.go (about)

     1  package odb
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"sort"
     8  	"strconv"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestTreeReturnsCorrectObjectType(t *testing.T) {
    16  	assert.Equal(t, TreeObjectType, new(Tree).Type())
    17  }
    18  
    19  func TestTreeEncoding(t *testing.T) {
    20  	tree := &Tree{
    21  		Entries: []*TreeEntry{
    22  			{
    23  				Name:     "a.dat",
    24  				Oid:      []byte("aaaaaaaaaaaaaaaaaaaa"),
    25  				Filemode: 0100644,
    26  			},
    27  			{
    28  				Name:     "subdir",
    29  				Oid:      []byte("bbbbbbbbbbbbbbbbbbbb"),
    30  				Filemode: 040000,
    31  			},
    32  			{
    33  				Name:     "submodule",
    34  				Oid:      []byte("cccccccccccccccccccc"),
    35  				Filemode: 0160000,
    36  			},
    37  		},
    38  	}
    39  
    40  	buf := new(bytes.Buffer)
    41  
    42  	n, err := tree.Encode(buf)
    43  	assert.Nil(t, err)
    44  	assert.NotEqual(t, 0, n)
    45  
    46  	assertTreeEntry(t, buf, "a.dat", []byte("aaaaaaaaaaaaaaaaaaaa"), 0100644)
    47  	assertTreeEntry(t, buf, "subdir", []byte("bbbbbbbbbbbbbbbbbbbb"), 040000)
    48  	assertTreeEntry(t, buf, "submodule", []byte("cccccccccccccccccccc"), 0160000)
    49  
    50  	assert.Equal(t, 0, buf.Len())
    51  }
    52  
    53  func TestTreeDecoding(t *testing.T) {
    54  	from := new(bytes.Buffer)
    55  	fmt.Fprintf(from, "%s %s\x00%s",
    56  		strconv.FormatInt(int64(0100644), 8),
    57  		"a.dat", []byte("aaaaaaaaaaaaaaaaaaaa"))
    58  	fmt.Fprintf(from, "%s %s\x00%s",
    59  		strconv.FormatInt(int64(040000), 8),
    60  		"subdir", []byte("bbbbbbbbbbbbbbbbbbbb"))
    61  	fmt.Fprintf(from, "%s %s\x00%s",
    62  		strconv.FormatInt(int64(0120000), 8),
    63  		"symlink", []byte("cccccccccccccccccccc"))
    64  	fmt.Fprintf(from, "%s %s\x00%s",
    65  		strconv.FormatInt(int64(0160000), 8),
    66  		"submodule", []byte("dddddddddddddddddddd"))
    67  
    68  	flen := from.Len()
    69  
    70  	tree := new(Tree)
    71  	n, err := tree.Decode(from, int64(flen))
    72  
    73  	assert.Nil(t, err)
    74  	assert.Equal(t, flen, n)
    75  
    76  	require.Equal(t, 4, len(tree.Entries))
    77  	assert.Equal(t, &TreeEntry{
    78  		Name:     "a.dat",
    79  		Oid:      []byte("aaaaaaaaaaaaaaaaaaaa"),
    80  		Filemode: 0100644,
    81  	}, tree.Entries[0])
    82  	assert.Equal(t, &TreeEntry{
    83  		Name:     "subdir",
    84  		Oid:      []byte("bbbbbbbbbbbbbbbbbbbb"),
    85  		Filemode: 040000,
    86  	}, tree.Entries[1])
    87  	assert.Equal(t, &TreeEntry{
    88  		Name:     "symlink",
    89  		Oid:      []byte("cccccccccccccccccccc"),
    90  		Filemode: 0120000,
    91  	}, tree.Entries[2])
    92  	assert.Equal(t, &TreeEntry{
    93  		Name:     "submodule",
    94  		Oid:      []byte("dddddddddddddddddddd"),
    95  		Filemode: 0160000,
    96  	}, tree.Entries[3])
    97  }
    98  
    99  func TestTreeDecodingShaBoundary(t *testing.T) {
   100  	var from bytes.Buffer
   101  
   102  	fmt.Fprintf(&from, "%s %s\x00%s",
   103  		strconv.FormatInt(int64(0100644), 8),
   104  		"a.dat", []byte("aaaaaaaaaaaaaaaaaaaa"))
   105  
   106  	flen := from.Len()
   107  
   108  	tree := new(Tree)
   109  	n, err := tree.Decode(bufio.NewReaderSize(&from, flen-2), int64(flen))
   110  
   111  	assert.Nil(t, err)
   112  	assert.Equal(t, flen, n)
   113  
   114  	require.Len(t, tree.Entries, 1)
   115  	assert.Equal(t, &TreeEntry{
   116  		Name:     "a.dat",
   117  		Oid:      []byte("aaaaaaaaaaaaaaaaaaaa"),
   118  		Filemode: 0100644,
   119  	}, tree.Entries[0])
   120  }
   121  
   122  func TestTreeMergeReplaceElements(t *testing.T) {
   123  	e1 := &TreeEntry{Name: "a", Filemode: 0100644, Oid: []byte{0x1}}
   124  	e2 := &TreeEntry{Name: "b", Filemode: 0100644, Oid: []byte{0x2}}
   125  	e3 := &TreeEntry{Name: "c", Filemode: 0100644, Oid: []byte{0x3}}
   126  
   127  	e4 := &TreeEntry{Name: "b", Filemode: 0100644, Oid: []byte{0x4}}
   128  	e5 := &TreeEntry{Name: "c", Filemode: 0100644, Oid: []byte{0x5}}
   129  
   130  	t1 := &Tree{Entries: []*TreeEntry{e1, e2, e3}}
   131  
   132  	t2 := t1.Merge(e4, e5)
   133  
   134  	require.Len(t, t1.Entries, 3)
   135  	assert.True(t, bytes.Equal(t1.Entries[0].Oid, []byte{0x1}))
   136  	assert.True(t, bytes.Equal(t1.Entries[1].Oid, []byte{0x2}))
   137  	assert.True(t, bytes.Equal(t1.Entries[2].Oid, []byte{0x3}))
   138  
   139  	require.Len(t, t2.Entries, 3)
   140  	assert.True(t, bytes.Equal(t2.Entries[0].Oid, []byte{0x1}))
   141  	assert.True(t, bytes.Equal(t2.Entries[1].Oid, []byte{0x4}))
   142  	assert.True(t, bytes.Equal(t2.Entries[2].Oid, []byte{0x5}))
   143  }
   144  
   145  func TestMergeInsertElementsInSubtreeOrder(t *testing.T) {
   146  	e1 := &TreeEntry{Name: "a-b", Filemode: 0100644, Oid: []byte{0x1}}
   147  	e2 := &TreeEntry{Name: "a", Filemode: 040000, Oid: []byte{0x2}}
   148  	e3 := &TreeEntry{Name: "a=", Filemode: 0100644, Oid: []byte{0x3}}
   149  	e4 := &TreeEntry{Name: "a-", Filemode: 0100644, Oid: []byte{0x4}}
   150  
   151  	t1 := &Tree{Entries: []*TreeEntry{e1, e2, e3}}
   152  	t2 := t1.Merge(e4)
   153  
   154  	require.Len(t, t1.Entries, 3)
   155  	assert.True(t, bytes.Equal(t1.Entries[0].Oid, []byte{0x1}))
   156  	assert.True(t, bytes.Equal(t1.Entries[1].Oid, []byte{0x2}))
   157  	assert.True(t, bytes.Equal(t1.Entries[2].Oid, []byte{0x3}))
   158  
   159  	assert.True(t, bytes.Equal(t2.Entries[0].Oid, []byte{0x4}))
   160  	assert.True(t, bytes.Equal(t2.Entries[1].Oid, []byte{0x1}))
   161  	assert.True(t, bytes.Equal(t2.Entries[2].Oid, []byte{0x2}))
   162  	assert.True(t, bytes.Equal(t2.Entries[3].Oid, []byte{0x3}))
   163  }
   164  
   165  type TreeEntryTypeTestCase struct {
   166  	Filemode int32
   167  	Expected ObjectType
   168  }
   169  
   170  func (c *TreeEntryTypeTestCase) Assert(t *testing.T) {
   171  	e := &TreeEntry{Filemode: c.Filemode}
   172  
   173  	got := e.Type()
   174  
   175  	assert.Equal(t, c.Expected, got,
   176  		"git/odb: expected type: %s, got: %s", c.Expected, got)
   177  }
   178  
   179  func TestTreeEntryTypeResolution(t *testing.T) {
   180  	for desc, c := range map[string]*TreeEntryTypeTestCase{
   181  		"blob":    {0100644, BlobObjectType},
   182  		"subtree": {040000, TreeObjectType},
   183  		"symlink": {0120000, BlobObjectType},
   184  		"commit":  {0160000, CommitObjectType},
   185  	} {
   186  		t.Run(desc, c.Assert)
   187  	}
   188  }
   189  
   190  func TestTreeEntryTypeResolutionUnknown(t *testing.T) {
   191  	e := &TreeEntry{Filemode: -1}
   192  
   193  	defer func() {
   194  		if err := recover(); err == nil {
   195  			t.Fatal("git/odb: expected panic(), got none")
   196  		} else {
   197  			assert.Equal(t, "git/odb: unknown object type: -1", err)
   198  		}
   199  	}()
   200  
   201  	e.Type()
   202  }
   203  
   204  func TestSubtreeOrder(t *testing.T) {
   205  	// The below list (e1, e2, ..., e5) is entered in subtree order: that
   206  	// is, lexicographically byte-ordered as if blobs end in a '\0', and
   207  	// sub-trees end in a '/'.
   208  	//
   209  	// See:
   210  	//   http://public-inbox.org/git/7vac6jfzem.fsf@assigned-by-dhcp.cox.net
   211  	e1 := &TreeEntry{Filemode: 0100644, Name: "a-"}
   212  	e2 := &TreeEntry{Filemode: 0100644, Name: "a-b"}
   213  	e3 := &TreeEntry{Filemode: 040000, Name: "a"}
   214  	e4 := &TreeEntry{Filemode: 0100644, Name: "a="}
   215  	e5 := &TreeEntry{Filemode: 0100644, Name: "a=b"}
   216  
   217  	// Create a set of entries in the wrong order:
   218  	entries := []*TreeEntry{e3, e4, e1, e5, e2}
   219  
   220  	sort.Sort(SubtreeOrder(entries))
   221  
   222  	// Assert that they are in the correct order after sorting in sub-tree
   223  	// order:
   224  	require.Len(t, entries, 5)
   225  	assert.Equal(t, "a-", entries[0].Name)
   226  	assert.Equal(t, "a-b", entries[1].Name)
   227  	assert.Equal(t, "a", entries[2].Name)
   228  	assert.Equal(t, "a=", entries[3].Name)
   229  	assert.Equal(t, "a=b", entries[4].Name)
   230  }
   231  
   232  func TestSubtreeOrderReturnsEmptyForOutOfBounds(t *testing.T) {
   233  	o := SubtreeOrder([]*TreeEntry{{Name: "a"}})
   234  
   235  	assert.Equal(t, "", o.Name(len(o)+1))
   236  }
   237  
   238  func TestSubtreeOrderReturnsEmptyForNilElements(t *testing.T) {
   239  	o := SubtreeOrder([]*TreeEntry{nil})
   240  
   241  	assert.Equal(t, "", o.Name(0))
   242  }
   243  
   244  func TestTreeEqualReturnsTrueWithUnchangedContents(t *testing.T) {
   245  	t1 := &Tree{Entries: []*TreeEntry{
   246  		{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   247  	}}
   248  	t2 := &Tree{Entries: []*TreeEntry{
   249  		{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   250  	}}
   251  
   252  	assert.True(t, t1.Equal(t2))
   253  }
   254  
   255  func TestTreeEqualReturnsFalseWithChangedContents(t *testing.T) {
   256  	t1 := &Tree{Entries: []*TreeEntry{
   257  		{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   258  		{Name: "b.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   259  	}}
   260  	t2 := &Tree{Entries: []*TreeEntry{
   261  		{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   262  		{Name: "c.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   263  	}}
   264  
   265  	assert.False(t, t1.Equal(t2))
   266  }
   267  
   268  func TestTreeEqualReturnsTrueWhenOneTreeIsNil(t *testing.T) {
   269  	t1 := &Tree{Entries: []*TreeEntry{
   270  		{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)},
   271  	}}
   272  	t2 := (*Tree)(nil)
   273  
   274  	assert.False(t, t1.Equal(t2))
   275  	assert.False(t, t2.Equal(t1))
   276  }
   277  
   278  func TestTreeEqualReturnsTrueWhenBothTreesAreNil(t *testing.T) {
   279  	t1 := (*Tree)(nil)
   280  	t2 := (*Tree)(nil)
   281  
   282  	assert.True(t, t1.Equal(t2))
   283  }
   284  
   285  func TestTreeEntryEqualReturnsTrueWhenEntriesAreTheSame(t *testing.T) {
   286  	e1 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   287  	e2 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   288  
   289  	assert.True(t, e1.Equal(e2))
   290  }
   291  
   292  func TestTreeEntryEqualReturnsFalseWhenDifferentNames(t *testing.T) {
   293  	e1 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   294  	e2 := &TreeEntry{Name: "b.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   295  
   296  	assert.False(t, e1.Equal(e2))
   297  }
   298  
   299  func TestTreeEntryEqualReturnsFalseWhenDifferentOids(t *testing.T) {
   300  	e1 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   301  	e2 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   302  
   303  	e2.Oid[0] = 1
   304  
   305  	assert.False(t, e1.Equal(e2))
   306  }
   307  
   308  func TestTreeEntryEqualReturnsFalseWhenDifferentFilemodes(t *testing.T) {
   309  	e1 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   310  	e2 := &TreeEntry{Name: "a.dat", Filemode: 0100755, Oid: make([]byte, 20)}
   311  
   312  	assert.False(t, e1.Equal(e2))
   313  }
   314  
   315  func TestTreeEntryEqualReturnsFalseWhenOneEntryIsNil(t *testing.T) {
   316  	e1 := &TreeEntry{Name: "a.dat", Filemode: 0100644, Oid: make([]byte, 20)}
   317  	e2 := (*TreeEntry)(nil)
   318  
   319  	assert.False(t, e1.Equal(e2))
   320  }
   321  
   322  func TestTreeEntryEqualReturnsTrueWhenBothEntriesAreNil(t *testing.T) {
   323  	e1 := (*TreeEntry)(nil)
   324  	e2 := (*TreeEntry)(nil)
   325  
   326  	assert.True(t, e1.Equal(e2))
   327  }
   328  
   329  func assertTreeEntry(t *testing.T, buf *bytes.Buffer,
   330  	name string, oid []byte, mode int32) {
   331  
   332  	fmode, err := buf.ReadBytes(' ')
   333  	assert.Nil(t, err)
   334  	assert.Equal(t, []byte(strconv.FormatInt(int64(mode), 8)+" "), fmode)
   335  
   336  	fname, err := buf.ReadBytes('\x00')
   337  	assert.Nil(t, err)
   338  	assert.Equal(t, []byte(name+"\x00"), fname)
   339  
   340  	var sha [20]byte
   341  	_, err = buf.Read(sha[:])
   342  	assert.Nil(t, err)
   343  	assert.Equal(t, oid, sha[:])
   344  }