github.com/weaviate/weaviate@v1.24.6/usecases/byteops/byteops_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package byteops 13 14 import ( 15 "crypto/rand" 16 "fmt" 17 "math/big" 18 "testing" 19 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 ) 23 24 const MaxUint32 = ^uint32(0) 25 26 func mustRandIntn(max int64) int { 27 randInt, err := rand.Int(rand.Reader, big.NewInt(max)) 28 if err != nil { 29 panic(fmt.Sprintf("mustRandIntn error: %v", err)) 30 } 31 return int(randInt.Int64()) 32 } 33 34 // Create a buffer with space for several values and first write into it and then test that the values can be read again 35 func TestReadAnWrite(t *testing.T) { 36 valuesNumbers := []uint64{234, 78, 23, 66, 8, 9, 2, 346745, 1} 37 valuesByteArray := make([]byte, mustRandIntn(500)) 38 rand.Read(valuesByteArray) 39 40 writeBuffer := make([]byte, 2*uint64Len+2*uint32Len+2*uint16Len+len(valuesByteArray)) 41 byteOpsWrite := NewReadWriter(writeBuffer) 42 43 byteOpsWrite.WriteUint64(valuesNumbers[0]) 44 byteOpsWrite.WriteUint32(uint32(valuesNumbers[1])) 45 byteOpsWrite.WriteUint32(uint32(valuesNumbers[2])) 46 assert.Equal(t, byteOpsWrite.CopyBytesToBuffer(valuesByteArray), nil) 47 byteOpsWrite.WriteUint16(uint16(valuesNumbers[3])) 48 byteOpsWrite.WriteUint64(valuesNumbers[4]) 49 byteOpsWrite.WriteUint16(uint16(valuesNumbers[5])) 50 51 byteOpsRead := NewReadWriter(writeBuffer) 52 53 require.Equal(t, byteOpsRead.ReadUint64(), valuesNumbers[0]) 54 require.Equal(t, byteOpsRead.ReadUint32(), uint32(valuesNumbers[1])) 55 require.Equal(t, byteOpsRead.ReadUint32(), uint32(valuesNumbers[2])) 56 57 // we are going to do the next op twice (once with copying, once without) 58 // to be able to rewind the buffer, let's cache the current position 59 posBeforeByteArray := byteOpsRead.Position 60 61 returnBuf, err := byteOpsRead.CopyBytesFromBuffer(uint64(len(valuesByteArray)), nil) 62 assert.Equal(t, returnBuf, valuesByteArray) 63 assert.Equal(t, err, nil) 64 65 // rewind the buffer to where it was before the read 66 byteOpsRead.MoveBufferToAbsolutePosition(posBeforeByteArray) 67 68 subSlice := byteOpsRead.ReadBytesFromBuffer(uint64(len(valuesByteArray))) 69 assert.Equal(t, subSlice, valuesByteArray) 70 71 // now read again using the other method 72 73 require.Equal(t, byteOpsRead.ReadUint16(), uint16(valuesNumbers[3])) 74 require.Equal(t, byteOpsRead.ReadUint64(), valuesNumbers[4]) 75 require.Equal(t, byteOpsRead.ReadUint16(), uint16(valuesNumbers[5])) 76 } 77 78 // create buffer that is larger than uint32 and write to the end and then try to reread it 79 func TestReadAnWriteLargeBuffer(t *testing.T) { 80 writeBuffer := make([]byte, uint64(MaxUint32)+4) 81 byteOpsWrite := NewReadWriter(writeBuffer) 82 byteOpsWrite.MoveBufferPositionForward(uint64(MaxUint32)) 83 byteOpsWrite.WriteUint16(uint16(10)) 84 85 byteOpsRead := NewReadWriter(writeBuffer) 86 byteOpsRead.MoveBufferPositionForward(uint64(MaxUint32)) 87 require.Equal(t, byteOpsRead.ReadUint16(), uint16(10)) 88 } 89 90 func TestWritingAndReadingBufferOfDynamicLength(t *testing.T) { 91 t.Run("uint64 length indicator", func(t *testing.T) { 92 bufLen := uint64(mustRandIntn(1024)) 93 buf := make([]byte, bufLen) 94 rand.Read(buf) 95 96 // uint64 length indicator + buffer + unrelated data at end of buffer 97 totalBuf := make([]byte, bufLen+16) 98 bo := NewReadWriter(totalBuf) 99 100 assert.Nil(t, bo.CopyBytesToBufferWithUint64LengthIndicator(buf)) 101 bo.WriteUint64(17) 102 assert.Equal(t, buf, totalBuf[8:8+bufLen]) 103 104 // read 105 bo = NewReadWriter(totalBuf) 106 bufRead := bo.ReadBytesFromBufferWithUint64LengthIndicator() 107 assert.Len(t, bufRead, int(bufLen)) 108 assert.Equal(t, uint64(17), bo.ReadUint64()) 109 110 // discard 111 bo = NewReadWriter(totalBuf) 112 discarded := bo.DiscardBytesFromBufferWithUint64LengthIndicator() 113 assert.Equal(t, bufLen, discarded) 114 assert.Equal(t, uint64(17), bo.ReadUint64()) 115 }) 116 117 t.Run("uint32 length indicator", func(t *testing.T) { 118 bufLen := uint32(mustRandIntn(1024)) 119 buf := make([]byte, bufLen) 120 rand.Read(buf) 121 122 // uint32 length indicator + buffer + unrelated data at end of buffer 123 totalBuf := make([]byte, bufLen+8) 124 bo := NewReadWriter(totalBuf) 125 126 assert.Nil(t, bo.CopyBytesToBufferWithUint32LengthIndicator(buf)) 127 bo.WriteUint32(17) 128 assert.Equal(t, buf, totalBuf[4:4+bufLen]) 129 130 // read 131 bo = NewReadWriter(totalBuf) 132 bufRead := bo.ReadBytesFromBufferWithUint32LengthIndicator() 133 assert.Len(t, bufRead, int(bufLen)) 134 assert.Equal(t, uint32(17), bo.ReadUint32()) 135 136 // discard 137 bo = NewReadWriter(totalBuf) 138 discarded := bo.DiscardBytesFromBufferWithUint32LengthIndicator() 139 assert.Equal(t, bufLen, discarded) 140 assert.Equal(t, uint32(17), bo.ReadUint32()) 141 }) 142 }