package enc import ( "bytes" "fmt" "math" "slices" "testing" bin "gordenko.dev/dima/bin/little" "gordenko.dev/dima/qb" ) func equalFloatSlices(a, b []float64, epsilon float64) bool { return slices.EqualFunc(a, b, func(x, y float64) bool { return math.Abs(x-y) <= epsilon }) } // CUMULATIVE var ( cumulativeTestCases = []struct { Nums []float64 Name string Offset int ChangeSize int Buf []byte BaseValue float64 LastDelta uint64 }{ { Nums: []float64{ 0, }, Name: "add 1st value zero", Offset: 0, ChangeSize: 3, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 0, LastDelta: 0, }, { Nums: []float64{ 1.5, }, Name: "add 1st value non zero", Offset: 0, ChangeSize: 3, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.5, }, Name: "literal switch to run", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x00, // run (len = 2) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.6, 1.6, }, Name: "literal decrease by 1 and switch to run", Offset: 2, ChangeSize: 3, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x81, // delta 1 0x00, // run (len = 2) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 1, }, { Nums: []float64{ 1.5, 1.5, 1.5, }, Name: "increment run", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.5, 1.5, 1.6, }, Name: "run switch to literal", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x81, // delta 1 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 1, }, { Nums: repeatFloat64(1.5, 129), Name: "increment run to full fill h-byte", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x7f, // run (len = 129) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: repeatFloat64(1.5, 130), Name: "run switch to literal after h-byte overflow", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x7f, // run (len = 129) 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.6, 1.7, }, Name: "increment literal", Offset: 1, ChangeSize: 2, Buf: []byte{ 0x8f, // base value 0x80, // delta 0 0x81, // delta 1 0x82, // delta 2 0x82, // literal (len = 3) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 2, }, } ) func TestCumulativeDeltaCompressor(t *testing.T) { for _, testCase := range cumulativeTestCases { var ( tmp = make([]byte, tmpValueSize) metricType = qb.Cumulative fracDigits byte = 1 buf = make([]byte, 8) payloadSize = 0 report qb.ValueEvaluationReport ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report = c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } if report.Offset != testCase.Offset { t.Fatalf("%s: got offset %d are not equal expected %d", testCase.Name, report.Offset, testCase.Offset) } if report.ChangeSize != testCase.ChangeSize { t.Fatalf("%s: got changeSize %d are not equal expected %d", testCase.Name, report.ChangeSize, testCase.ChangeSize) } if !bytes.Equal(buf, testCase.Buf) { t.Fatalf("%s: got buf % x are not equal expected % x", testCase.Name, buf, testCase.Buf) } if c.baseValue != testCase.BaseValue { t.Fatalf("%s: got baseValue %v are not equal expected %v", testCase.Name, c.baseValue, testCase.BaseValue) } if c.lastDelta != testCase.LastDelta { t.Fatalf("%s: got lastDelta %d are not equal expected %d", testCase.Name, c.lastDelta, testCase.LastDelta) } } } func TestRestoreCumulativeDeltaCompressor(t *testing.T) { for _, testCase := range cumulativeTestCases { var ( tmp = make([]byte, tmpValueSize) metricType = qb.Cumulative fracDigits byte = 1 buf = make([]byte, 8) payloadSize = 0 report qb.ValueEvaluationReport ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report = c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } restored := NewValueDeltaCompressor(metricType, fracDigits, buf, c.Size()) if restored.baseValue != testCase.BaseValue { t.Fatalf("%s: got baseValue %v are not equal expected %v", testCase.Name, restored.baseValue, testCase.BaseValue) } if restored.lastDelta != testCase.LastDelta { t.Fatalf("%s: got lastDelta %d are not equal expected %d", testCase.Name, restored.lastDelta, testCase.LastDelta) } } } func TestCumulativeDeltaDecompressorFromState(t *testing.T) { for _, testCase := range cumulativeTestCases { var ( metricType = qb.Cumulative fracDigits byte = 1 tmp = make([]byte, tmpValueSize) buf = make([]byte, 16) payloadSize = 0 decodedNums []float64 ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report := c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } d := c.CreateDecompressor(metricType, fracDigits) for { num, done := d.NextValue() if done { break } decodedNums = append(decodedNums, num) } slices.Reverse(decodedNums) if !equalFloatSlices(testCase.Nums, decodedNums, 0.0000001) { t.Fatalf("%s: got nums %v not equal expected %v", testCase.Name, decodedNums, testCase.Nums) } } } func TestCumulativeDeltaDecompressorFromEnd(t *testing.T) { for _, testCase := range cumulativeTestCases { var ( metricType = qb.Cumulative fracDigits byte = 1 tmp = make([]byte, tmpValueSize) buf = make([]byte, 16) payloadSize = 0 decodedNums []float64 ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report := c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } d := NewValueDeltaDecompressor(metricType, fracDigits) d.RestoreFromEnd(buf[:c.Size()]) for { num, done := d.NextValue() if done { break } decodedNums = append(decodedNums, num) } slices.Reverse(decodedNums) if !equalFloatSlices(testCase.Nums, decodedNums, 0.0000001) { t.Fatalf("%s: got nums %v not equal expected %v", testCase.Name, decodedNums, testCase.Nums) } } } // INSTANT var ( instantTestCases = []struct { Nums []float64 Name string Offset int ChangeSize int Buf []byte BaseValue float64 LastDelta uint64 }{ { Nums: []float64{ 1.5, }, Name: "add 1st value", Offset: 0, ChangeSize: 3, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ -1.5, }, Name: "add 1st value (negative)", Offset: 0, ChangeSize: 3, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.5, }, Name: "literal switch to run", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x00, // run (len = 2) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ -1.5, -1.5, }, Name: "literal switch to run (negative)", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x00, // run (len = 2) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.6, 1.6, }, Name: "literal decrease by 1 and switch to run", Offset: 2, ChangeSize: 3, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x82, // delta 1 0x00, // run (len = 2) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: bin.EncodeZigZag(1), }, { Nums: []float64{ -1.5, -1.6, -1.6, }, Name: "literal decrease by 1 and switch to run (negative)", Offset: 2, ChangeSize: 3, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x81, // delta -1 0x00, // run (len = 2) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: bin.EncodeZigZag(-1), }, { Nums: []float64{ 1.5, 1.4, 1.4, }, Name: "literal decrease by 1 and switch to run (negative delta)", Offset: 2, ChangeSize: 3, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x81, // delta -1 0x00, // run (len = 2) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: bin.EncodeZigZag(-1), }, { Nums: []float64{ -1.5, -1.4, -1.4, }, Name: "literal decrease by 1 and switch to run (positive delta, negative)", Offset: 2, ChangeSize: 3, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x80, // literal (len = 1) 0x82, // delta 1 0x00, // run (len = 2) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: bin.EncodeZigZag(1), }, { Nums: []float64{ 1.5, 1.5, 1.5, }, Name: "increment run", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: []float64{ -1.5, -1.5, -1.5, }, Name: "increment run (negative)", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.5, 1.5, 1.6, }, Name: "run switch to literal", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x82, // delta 1 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: bin.EncodeZigZag(1), }, { Nums: []float64{ -1.5, -1.5, -1.5, -1.6, }, Name: "run switch to literal (negative)", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x81, // delta -1 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: bin.EncodeZigZag(-1), }, { Nums: []float64{ 1.5, 1.5, 1.5, 1.4, }, Name: "run switch to literal (negative delta)", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x81, // delta -1 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: bin.EncodeZigZag(-1), }, { Nums: []float64{ -1.5, -1.5, -1.5, -1.4, }, Name: "run switch to literal (positive delta, negative version)", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x01, // run (len = 3) 0x82, // delta 1 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: bin.EncodeZigZag(1), }, { Nums: repeatFloat64(1.5, 129), Name: "increment run to full fill h-byte", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x7f, // run (len = 129) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: repeatFloat64(-1.5, 129), Name: "increment run to full fill h-byte (negative version)", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x7f, // run (len = 129) 0x00, 0x00, 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: 0, }, { Nums: repeatFloat64(1.5, 130), Name: "run switch to literal after h-byte overflow", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x7f, // run (len = 129) 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: 0, }, { Nums: repeatFloat64(-1.5, 130), Name: "run switch to literal after h-byte overflow (negative version)", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x7f, // run (len = 129) 0x80, // delta 0 0x80, // literal (len = 1) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: 0, }, { Nums: []float64{ 1.5, 1.6, 1.7, }, Name: "increment literal", Offset: 1, ChangeSize: 2, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x82, // delta 1 0x84, // delta 2 0x82, // literal (len = 3) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: bin.EncodeZigZag(2), }, { Nums: []float64{ -1.5, -1.6, -1.7, }, Name: "increment literal (negative version)", Offset: 1, ChangeSize: 2, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x81, // delta -1 0x83, // delta -2 0x82, // literal (len = 3) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: bin.EncodeZigZag(-2), }, { Nums: []float64{ 1.5, 1.4, 1.3, }, Name: "increment literal (negative delta)", Offset: 1, ChangeSize: 2, Buf: []byte{ 0x9e, // base value 0x80, // delta 0 0x81, // delta -1 0x83, // delta -2 0x82, // literal (len = 3) 0x00, 0x00, 0x00, }, BaseValue: 1.5, LastDelta: bin.EncodeZigZag(-2), }, { Nums: []float64{ -1.5, -1.4, -1.3, }, Name: "increment literal (positive delta, negative version)", Offset: 1, ChangeSize: 2, Buf: []byte{ 0x9d, // base value 0x80, // delta 0 0x82, // delta 1 0x84, // delta 2 0x82, // literal (len = 3) 0x00, 0x00, 0x00, }, BaseValue: -1.5, LastDelta: bin.EncodeZigZag(2), }, } ) func TestInstantDeltaCompressor(t *testing.T) { for _, testCase := range instantTestCases { var ( tmp = make([]byte, tmpValueSize) metricType = qb.Instant fracDigits byte = 1 buf = make([]byte, 8) payloadSize = 0 report qb.ValueEvaluationReport ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report = c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } if report.Offset != testCase.Offset { t.Fatalf("%s: got offset %d are not equal expected %d", testCase.Name, report.Offset, testCase.Offset) } if report.ChangeSize != testCase.ChangeSize { t.Fatalf("%s: got changeSize %d are not equal expected %d", testCase.Name, report.ChangeSize, testCase.ChangeSize) } if !bytes.Equal(buf, testCase.Buf) { t.Fatalf("%s: got buf % x are not equal expected % x", testCase.Name, buf, testCase.Buf) } if c.baseValue != testCase.BaseValue { t.Fatalf("%s: got baseValue %v are not equal expected %v", testCase.Name, c.baseValue, testCase.BaseValue) } if c.lastDelta != testCase.LastDelta { t.Fatalf("%s: got lastDelta %d are not equal expected %d", testCase.Name, c.lastDelta, testCase.LastDelta) } } } func TestRestoreInstantDeltaCompressor(t *testing.T) { for _, testCase := range instantTestCases { var ( tmp = make([]byte, tmpValueSize) metricType = qb.Instant fracDigits byte = 1 buf = make([]byte, 8) payloadSize = 0 report qb.ValueEvaluationReport ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report = c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } restored := NewValueDeltaCompressor(metricType, fracDigits, buf, c.Size()) if restored.baseValue != testCase.BaseValue { t.Fatalf("%s: got baseValue %v are not equal expected %v", testCase.Name, restored.baseValue, testCase.BaseValue) } if restored.lastDelta != testCase.LastDelta { t.Fatalf("%s: got lastDelta %d are not equal expected %d", testCase.Name, restored.lastDelta, testCase.LastDelta) } } } func TestInstantDeltaDecompressorFromState(t *testing.T) { for _, testCase := range instantTestCases { var ( metricType = qb.Instant fracDigits byte = 1 tmp = make([]byte, tmpValueSize) buf = make([]byte, 16) payloadSize = 0 decodedNums []float64 ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report := c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } d := c.CreateDecompressor(metricType, fracDigits) for { num, done := d.NextValue() if done { break } decodedNums = append(decodedNums, num) } slices.Reverse(decodedNums) if !equalFloatSlices(testCase.Nums, decodedNums, 0.0000001) { t.Fatalf("%s: got nums %v not equal expected %v", testCase.Name, decodedNums, testCase.Nums) } } } func TestInstantDeltaDecompressorFromEnd(t *testing.T) { for _, testCase := range instantTestCases { var ( metricType = qb.Instant fracDigits byte = 1 tmp = make([]byte, tmpValueSize) buf = make([]byte, 8) payloadSize = 0 decodedNums []float64 ) c := NewValueDeltaCompressor(metricType, fracDigits, buf, payloadSize) for _, num := range testCase.Nums { report := c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num, report.Delta) } d := NewValueDeltaDecompressor(metricType, fracDigits) d.RestoreFromEnd(buf[:c.Size()]) for { num, done := d.NextValue() if done { break } decodedNums = append(decodedNums, num) } slices.Reverse(decodedNums) if !equalFloatSlices(testCase.Nums, decodedNums, 0.0000001) { t.Fatalf("%s: got nums %v not equal expected %v", testCase.Name, decodedNums, testCase.Nums) } } } // TIME DELTA var ( timeTestCases = []struct { Name string Nums []uint32 Buf []byte LastUnixtime uint32 LastDelta uint32 Offset int ChangeSize int }{ { Nums: []uint32{ 1780777000, }, Name: "add 1st value", Offset: 0, ChangeSize: 4, Buf: []byte{ 0x00, 0x00, 0x00, 0x00, 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777000, LastDelta: 0, }, { Nums: []uint32{ 1780777000, 1780777060, // +60 }, Name: "add 1st delta", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x00, 0x00, 0x80, // h-byte (literal, len=1) 0xbc, // delta (60) 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777060, LastDelta: 60, }, { Nums: []uint32{ 1780777000, 1780777060, // +60 1780777120, // +60 }, Name: "literal changed to run", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x00, 0x00, 0x00, // h-byte (run, len=2) 0xbc, // delta 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777120, LastDelta: 60, }, { Nums: []uint32{ 1780777000, 1780777060, // +60 1780777130, // +70 1780777200, // +70 }, Name: "literal decrease by 1 and switch to run", Offset: 2, ChangeSize: 3, Buf: []byte{ 0x00, // h-byte (run, len=2) 0xc6, // delta 70 0x80, // h-byte (literal, len=1) 0xbc, // delta 60 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777200, LastDelta: 70, }, { Nums: []uint32{ 1780777000, 1780777060, // +60 1780777120, // +60 1780777180, // +60 }, Name: "increment run", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x00, 0x00, 0x01, // h-byte (run, len=2) 0xbc, // delta 60 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777180, LastDelta: 60, }, { Nums: []uint32{ 1780777000, 1780777060, // +60 1780777120, // +60 1780777180, // +60 1780777200, // +20 }, Name: "switch run to literal", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x80, // h-byte (literal, len=1) 0x94, // delta 20 0x01, // h-byte (run, len=3) 0xbc, // delta 60 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777200, LastDelta: 20, }, { Nums: generateProgression(1780777000, 60, 130), Name: "increment run up to full filled h-byte", Offset: 1, ChangeSize: 1, Buf: []byte{ 0x00, 0x00, 0x7f, // h-byte (run, len=129) 0xbc, // delta 60 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777000 + 129*60, LastDelta: 60, }, { Nums: generateProgression(1780777000, 60, 131), Name: "run switch to literal after h-byte overflow", Offset: 0, ChangeSize: 2, Buf: []byte{ 0x80, // h-byte (literal, len=1) 0xbc, // delta 60 0x7f, // h-byte (run, len=129) 0xbc, // delta 60 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777000 + 130*60, LastDelta: 60, }, { Nums: []uint32{ 1780777000, 1780777060, // +60 1780777130, // +70 }, Name: "increment literal", Offset: 1, ChangeSize: 2, Buf: []byte{ 0x00, 0x81, // h-byte (literal, len=2) 0xc6, // delta 70 0xbc, // delta 60 0x28, 0x80, 0x24, 0x6a, // since }, LastUnixtime: 1780777130, LastDelta: 70, }, } ) func TestTimeDeltaCompressor(t *testing.T) { for _, testCase := range timeTestCases { var ( tmp = make([]byte, tmpTimeSize) buf = make([]byte, 8) payloadSize = 0 report qb.TimeEvaluationReport ) c := NewTimeDeltaCompressor(buf, payloadSize) for _, num := range testCase.Nums { report = c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num) } if report.Offset != testCase.Offset { t.Fatalf("%s: got offset %d are not equal expected %d", testCase.Name, report.Offset, testCase.Offset) } if report.ChangeSize != testCase.ChangeSize { t.Fatalf("%s: got changeSize %d are not equal expected %d", testCase.Name, report.ChangeSize, testCase.ChangeSize) } if !bytes.Equal(buf, testCase.Buf) { t.Fatalf("%s: got buf % x are not equal expected % x", testCase.Name, buf, testCase.Buf) } if c.lastUnixtime != testCase.LastUnixtime { t.Fatalf("%s: got lastUnixtime %d are not equal expected %d", testCase.Name, c.lastUnixtime, testCase.LastUnixtime) } if c.lastDelta != testCase.LastDelta { t.Fatalf("%s: got lastDelta %d are not equal expected %d", testCase.Name, c.lastDelta, testCase.LastDelta) } } } func TestRestoreTimeDeltaCompressor(t *testing.T) { for _, testCase := range timeTestCases { var ( tmp = make([]byte, tmpTimeSize) buf = make([]byte, 8) payloadSize = 0 report qb.TimeEvaluationReport ) c := NewTimeDeltaCompressor(buf, payloadSize) for _, num := range testCase.Nums { report = c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num) } restored := NewTimeDeltaCompressor(buf, c.Size()) if restored.lastUnixtime != testCase.LastUnixtime { t.Fatalf("%s: got lastUnixtime %d are not equal expected %d", testCase.Name, restored.lastUnixtime, testCase.LastUnixtime) } if restored.lastDelta != testCase.LastDelta { t.Fatalf("%s: got lastDelta %d are not equal expected %d", testCase.Name, restored.lastDelta, testCase.LastDelta) } } } func TestTimeDeltaDecompressorFromState(t *testing.T) { for _, testCase := range timeTestCases { var ( tmp = make([]byte, tmpTimeSize) buf = make([]byte, 8) payloadSize = 0 decodedNums []uint32 ) c := NewTimeDeltaCompressor(buf, payloadSize) for _, num := range testCase.Nums { report := c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num) } d := c.CreateDecompressor() for { num, done := d.NextValue() if done { break } decodedNums = append(decodedNums, num) } slices.Reverse(decodedNums) if !slices.Equal(testCase.Nums, decodedNums) { t.Fatalf("%s: got nums %v not equal expected %v", testCase.Name, decodedNums, testCase.Nums) } } } func TestTimeDeltaDecompressorFromEnd(t *testing.T) { for _, testCase := range timeTestCases { var ( tmp = make([]byte, tmpTimeSize) buf = make([]byte, 8) payloadSize = 0 decodedNums []uint32 ) c := NewTimeDeltaCompressor(buf, payloadSize) for _, num := range testCase.Nums { report := c.Evaluate(tmp, num) c.Append(report.Offset, tmp[:report.ChangeSize], num) } c.ReplaceSinceWithUntil() d := NewTimeDeltaDecompressor() d.RestoreFromEnd(buf[len(buf)-c.Size():]) for { num, done := d.NextValue() if done { break } decodedNums = append(decodedNums, num) } slices.Reverse(decodedNums) if !slices.Equal(testCase.Nums, decodedNums) { t.Fatalf("%s: got nums %v not equal expected %v", testCase.Name, decodedNums, testCase.Nums) } } } func TestVarInt64(t *testing.T) { arr := make([]byte, 9) n, err := bin.PutVarInt64(arr, -15) if err != nil { t.Fatal(err) } fmt.Println(arr[:n]) } func repeatFloat64(num float64, n int) []float64 { nums := make([]float64, n) for i := range nums { nums[i] = num } return nums } func generateProgression(start uint32, delta uint32, n int) []uint32 { nums := make([]uint32, n) nums[0] = start for i := 1; i < n; i++ { nums[i] = nums[i-1] + delta } return nums }