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 }