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

     1  package pack
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"testing"
     7  
     8  	"github.com/git-lfs/git-lfs/errors"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  var (
    14  	idx *Index
    15  )
    16  
    17  func TestIndexEntrySearch(t *testing.T) {
    18  	e, err := idx.Entry([]byte{
    19  		0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
    20  		0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
    21  	})
    22  
    23  	assert.NoError(t, err)
    24  	assert.EqualValues(t, 6, e.PackOffset)
    25  }
    26  
    27  func TestIndexEntrySearchClampLeft(t *testing.T) {
    28  	e, err := idx.Entry([]byte{
    29  		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    30  		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    31  	})
    32  
    33  	assert.NoError(t, err)
    34  	assert.EqualValues(t, 0, e.PackOffset)
    35  }
    36  
    37  func TestIndexEntrySearchClampRight(t *testing.T) {
    38  	e, err := idx.Entry([]byte{
    39  		0xff, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
    40  		0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
    41  	})
    42  
    43  	assert.NoError(t, err)
    44  	assert.EqualValues(t, 0x4ff, e.PackOffset)
    45  }
    46  
    47  func TestIndexSearchOutOfBounds(t *testing.T) {
    48  	e, err := idx.Entry([]byte{
    49  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    50  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    51  	})
    52  
    53  	assert.True(t, IsNotFound(err), "expected err to be 'not found'")
    54  	assert.Nil(t, e)
    55  }
    56  
    57  func TestIndexEntryNotFound(t *testing.T) {
    58  	e, err := idx.Entry([]byte{
    59  		0x1, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6,
    60  		0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6,
    61  	})
    62  
    63  	assert.True(t, IsNotFound(err), "expected err to be 'not found'")
    64  	assert.Nil(t, e)
    65  }
    66  
    67  func TestIndexCount(t *testing.T) {
    68  	fanout := make([]uint32, 256)
    69  	for i := 0; i < len(fanout); i++ {
    70  		fanout[i] = uint32(i)
    71  	}
    72  
    73  	idx := &Index{fanout: fanout}
    74  
    75  	assert.EqualValues(t, 255, idx.Count())
    76  }
    77  
    78  func TestIndexIsNotFound(t *testing.T) {
    79  	assert.True(t, IsNotFound(errNotFound),
    80  		"expected 'errNotFound' to satisfy 'IsNotFound()'")
    81  }
    82  
    83  func TestIndexIsNotFoundForOtherErrors(t *testing.T) {
    84  	assert.False(t, IsNotFound(errors.New("git/odb/pack: misc")),
    85  		"expected 'err' not to satisfy 'IsNotFound()'")
    86  }
    87  
    88  // init generates some fixture data and then constructs an *Index instance using
    89  // it.
    90  func init() {
    91  	// eps is the number of SHA1 names generated under each 0x<t> slot.
    92  	const eps = 5
    93  
    94  	hdr := []byte{
    95  		0xff, 0x74, 0x4f, 0x63, // Index file v2+ magic header
    96  		0x00, 0x00, 0x00, 0x02, // 4-byte version indicator
    97  	}
    98  
    99  	// Create a fanout table using uint32s (later marshalled using
   100  	// binary.BigEndian).
   101  	//
   102  	// Since we have an even distribution of SHA1s in the generated index,
   103  	// each entry will increase by the number of entries per slot (see: eps
   104  	// above).
   105  	fanout := make([]uint32, indexFanoutEntries)
   106  	for i := 0; i < len(fanout); i++ {
   107  		// Begin the index at (i+1), since the fanout table mandates
   108  		// objects less than the value at index "i".
   109  		fanout[i] = uint32((i + 1) * eps)
   110  	}
   111  
   112  	offs := make([]uint32, 0, 256*eps)
   113  	crcs := make([]uint32, 0, 256*eps)
   114  
   115  	names := make([][]byte, 0, 256*eps)
   116  	for i := 0; i < 256; i++ {
   117  		// For each name, generate a unique SHA using the prefix "i",
   118  		// and then suffix "j".
   119  		//
   120  		// In other words, when i=1, we will generate:
   121  		//   []byte{0x1 0x0 0x0 0x0 ...}
   122  		//   []byte{0x1 0x1 0x1 0x1 ...}
   123  		//   []byte{0x1 0x2 0x2 0x2 ...}
   124  		//
   125  		// and etc.
   126  		for j := 0; j < eps; j++ {
   127  			var sha [20]byte
   128  
   129  			sha[0] = byte(i)
   130  			for r := 1; r < len(sha); r++ {
   131  				sha[r] = byte(j)
   132  			}
   133  
   134  			cpy := make([]byte, len(sha))
   135  			copy(cpy, sha[:])
   136  
   137  			names = append(names, cpy)
   138  			offs = append(offs, uint32((i*eps)+j))
   139  			crcs = append(crcs, 0)
   140  		}
   141  	}
   142  
   143  	// Create a buffer to hold the index contents:
   144  	buf := bytes.NewBuffer(hdr)
   145  
   146  	// Write each value in the fanout table using a 32bit network byte-order
   147  	// integer.
   148  	for _, f := range fanout {
   149  		binary.Write(buf, binary.BigEndian, f)
   150  	}
   151  	// Write each SHA1 name to the table next.
   152  	for _, name := range names {
   153  		buf.Write(name)
   154  	}
   155  	// Then write each of the CRC values in network byte-order as a 32bit
   156  	// unsigned integer.
   157  	for _, crc := range crcs {
   158  		binary.Write(buf, binary.BigEndian, crc)
   159  	}
   160  	// Do the same with the offsets.
   161  	for _, off := range offs {
   162  		binary.Write(buf, binary.BigEndian, off)
   163  	}
   164  
   165  	idx = &Index{
   166  		fanout: fanout,
   167  		// version is unimportant here, use V2 since it's more common in
   168  		// the wild.
   169  		version: new(V2),
   170  
   171  		// *bytes.Buffer does not implement io.ReaderAt, but
   172  		// *bytes.Reader does.
   173  		//
   174  		// Call (*bytes.Buffer).Bytes() to get the data, and then
   175  		// construct a new *bytes.Reader with it to implement
   176  		// io.ReaderAt.
   177  		r: bytes.NewReader(buf.Bytes()),
   178  	}
   179  }