[#248] object: Introduce SplitByMaxChunkLength method

* Add unit-test to test `SplitByMaxChunkLength`.

Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
Airat Arifullin 2024-08-05 15:46:37 +03:00
parent 5e9cf6a8ae
commit 895a2ef0e2
2 changed files with 103 additions and 0 deletions

View file

@ -78,6 +78,42 @@ type PayloadPatch struct {
Chunk []byte
}
// SplitByMaxChunkLength splits a payload patch into a few payload patches if its `Chunk` size
// exceeds `maxChunkLen`.
func (p *PayloadPatch) SplitByMaxChunkLength(maxChunkLen int) []*PayloadPatch {
if len(p.Chunk) <= maxChunkLen {
return []*PayloadPatch{p}
}
var result []*PayloadPatch
remainingChunk := p.Chunk
currentOffset := p.Range.GetOffset()
remainingLength := p.Range.GetLength()
for len(remainingChunk) > 0 {
chunkSize := uint64(min(len(remainingChunk), maxChunkLen))
newLength := min(remainingLength, chunkSize)
rng := NewRange()
rng.SetOffset(currentOffset)
rng.SetLength(newLength)
newPatch := &PayloadPatch{
Range: rng,
Chunk: remainingChunk[:chunkSize],
}
result = append(result, newPatch)
remainingChunk = remainingChunk[chunkSize:]
currentOffset += chunkSize
if remainingLength > 0 {
remainingLength -= newLength
}
}
return result
}
func (p *PayloadPatch) ToV2() *v2object.PatchRequestBodyPatch {
if p == nil {
return nil

View file

@ -10,6 +10,73 @@ import (
"github.com/stretchr/testify/require"
)
func newRange(offest, length uint64) *Range {
rng := &Range{}
rng.SetOffset(offest)
rng.SetLength(length)
return rng
}
func TestSplitByMaxChunkLength(t *testing.T) {
t.Run("no break down", func(t *testing.T) {
payloadPatch := &PayloadPatch{
Range: newRange(0, 42),
Chunk: []byte("100000|010000|001000|000100|000010|000001|"),
}
payloadPatches := payloadPatch.SplitByMaxChunkLength(42)
require.Len(t, payloadPatches, 1)
require.Equal(t, []byte("100000|010000|001000|000100|000010|000001|"), payloadPatches[0].Chunk)
require.Equal(t, uint64(0), payloadPatches[0].Range.GetOffset())
require.Equal(t, uint64(42), payloadPatches[0].Range.GetLength())
})
t.Run("one replacing and two inserting patches", func(t *testing.T) {
payloadPatch := &PayloadPatch{
Range: newRange(0, 15),
Chunk: []byte("100000|010000|001000|000100|000010|000001|"),
}
payloadPatches := payloadPatch.SplitByMaxChunkLength(15)
require.Len(t, payloadPatches, 3)
require.Equal(t, []byte("100000|010000|0"), payloadPatches[0].Chunk)
require.Equal(t, uint64(0), payloadPatches[0].Range.GetOffset())
require.Equal(t, uint64(15), payloadPatches[0].Range.GetLength())
require.Equal(t, []byte("01000|000100|00"), payloadPatches[1].Chunk)
require.Equal(t, uint64(15), payloadPatches[1].Range.GetOffset())
require.Equal(t, uint64(0), payloadPatches[1].Range.GetLength())
require.Equal(t, []byte("0010|000001|"), payloadPatches[2].Chunk)
require.Equal(t, uint64(30), payloadPatches[2].Range.GetOffset())
require.Equal(t, uint64(0), payloadPatches[2].Range.GetLength())
})
t.Run("one replacing and one inserting patches", func(t *testing.T) {
payloadPatch := &PayloadPatch{
Range: newRange(0, 30),
Chunk: []byte("100000|010000|001000|000100|000010|000001|"),
}
payloadPatches := payloadPatch.SplitByMaxChunkLength(30)
require.Len(t, payloadPatches, 2)
require.Equal(t, []byte("100000|010000|001000|000100|00"), payloadPatches[0].Chunk)
require.Equal(t, uint64(0), payloadPatches[0].Range.GetOffset())
require.Equal(t, uint64(30), payloadPatches[0].Range.GetLength())
require.Equal(t, []byte("0010|000001|"), payloadPatches[1].Chunk)
require.Equal(t, uint64(30), payloadPatches[1].Range.GetOffset())
require.Equal(t, uint64(0), payloadPatches[1].Range.GetLength())
})
}
func TestPatch(t *testing.T) {
t.Run("to v2", func(t *testing.T) {
t.Run("only attributes", func(t *testing.T) {