fix small bug, 100% test coverage
This commit is contained in:
@@ -27,12 +27,6 @@ func Encode(w io.Writer, v uint64) {
|
||||
|
||||
func Decode(r io.Reader) (v uint64, err error) {
|
||||
x := []byte{0}
|
||||
// _, _ = r.Read(x)
|
||||
// if x[0] > 128 {
|
||||
// v += uint64(x[0] & 127)
|
||||
// return
|
||||
// } else {
|
||||
v += uint64(x[0])
|
||||
var i uint64
|
||||
for {
|
||||
if _, err = r.Read(x); chk.E(err) {
|
||||
@@ -46,5 +40,4 @@ func Decode(r io.Reader) (v uint64, err error) {
|
||||
i++
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -2,28 +2,228 @@ package varint
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"lukechampine.com/frand"
|
||||
|
||||
"realy.lol/chk"
|
||||
)
|
||||
|
||||
func TestEncode_Decode(t *testing.T) {
|
||||
var v uint64
|
||||
for range 10000000 {
|
||||
v = uint64(frand.Intn(math.MaxInt64))
|
||||
buf1 := new(bytes.Buffer)
|
||||
Encode(buf1, v)
|
||||
buf2 := bytes.NewBuffer(buf1.Bytes())
|
||||
u, err := Decode(buf2)
|
||||
if chk.E(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if u != v {
|
||||
t.Fatalf("expected %d got %d", v, u)
|
||||
}
|
||||
func TestEncode_Decode_Comprehensive(t *testing.T) {
|
||||
// Test specific edge cases
|
||||
testCases := []uint64{
|
||||
0, // minimum value
|
||||
1, // simple case
|
||||
127, // max single byte value (before terminal bit)
|
||||
128, // first two-byte value
|
||||
255, // max value in first byte + some in second
|
||||
256, // clean two-byte boundary
|
||||
16383, // max two-byte value
|
||||
16384, // first three-byte value
|
||||
math.MaxUint32, // 32-bit max
|
||||
math.MaxUint64, // 64-bit max
|
||||
math.MaxUint64 - 1, // near max
|
||||
1<<7 - 1, // 127
|
||||
1<<14 - 1, // 16383
|
||||
1<<21 - 1, // 2097151
|
||||
1<<28 - 1, // 268435455
|
||||
1<<35 - 1, // 34359738367
|
||||
1<<42 - 1, // 4398046511103
|
||||
1<<49 - 1, // 562949953421311
|
||||
1<<56 - 1, // 72057594037927935
|
||||
}
|
||||
|
||||
for _, v := range testCases {
|
||||
t.Run(fmt.Sprintf("value_%d", v), func(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
Encode(buf, v)
|
||||
|
||||
decoded, err := Decode(bytes.NewBuffer(buf.Bytes()))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to decode %d: %v", v, err)
|
||||
}
|
||||
if decoded != v {
|
||||
t.Fatalf("Value %d: expected %d, got %d", v, v, decoded)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_Decode_Random(t *testing.T) {
|
||||
// Test with random values (reduced from 10M to 100K for faster testing)
|
||||
for i := 0; i < 100000; i++ {
|
||||
v := uint64(frand.Intn(math.MaxInt64))
|
||||
buf := new(bytes.Buffer)
|
||||
Encode(buf, v)
|
||||
|
||||
decoded, err := Decode(bytes.NewBuffer(buf.Bytes()))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to decode %d: %v", v, err)
|
||||
}
|
||||
if decoded != v {
|
||||
t.Fatalf("Value %d: expected %d, got %d", v, v, decoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode_ErrorConditions(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reader io.Reader
|
||||
wantErr bool
|
||||
errType error
|
||||
}{
|
||||
{
|
||||
name: "empty_reader",
|
||||
reader: strings.NewReader(""),
|
||||
wantErr: true,
|
||||
errType: io.EOF,
|
||||
},
|
||||
{
|
||||
name: "empty_buffer",
|
||||
reader: &bytes.Buffer{},
|
||||
wantErr: true,
|
||||
errType: io.EOF,
|
||||
},
|
||||
{
|
||||
name: "single_byte_incomplete",
|
||||
reader: bytes.NewBuffer([]byte{0}), // non-terminal byte with no following bytes
|
||||
wantErr: true,
|
||||
errType: io.EOF,
|
||||
},
|
||||
{
|
||||
name: "multi_byte_incomplete",
|
||||
reader: bytes.NewBuffer([]byte{0, 0}), // two non-terminal bytes with no terminal
|
||||
wantErr: true,
|
||||
errType: io.EOF,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := Decode(tt.reader)
|
||||
if !tt.wantErr {
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %v", err)
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Error("Expected error, got nil")
|
||||
}
|
||||
if tt.errType != nil && err != tt.errType {
|
||||
t.Errorf("Expected error %v, got %v", tt.errType, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_SingleByte(t *testing.T) {
|
||||
// Test that values 0-127 encode to single bytes
|
||||
for i := uint64(0); i <= 127; i++ {
|
||||
buf := new(bytes.Buffer)
|
||||
Encode(buf, i)
|
||||
encoded := buf.Bytes()
|
||||
|
||||
if len(encoded) != 1 {
|
||||
t.Errorf("Value %d should encode to 1 byte, got %d bytes: %v", i, len(encoded), encoded)
|
||||
}
|
||||
|
||||
expected := byte(i) | 128 // value with terminal bit set
|
||||
if encoded[0] != expected {
|
||||
t.Errorf("Value %d: expected byte %d, got %d", i, expected, encoded[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_MultiByte(t *testing.T) {
|
||||
// Test specific multi-byte cases
|
||||
tests := []struct {
|
||||
value uint64
|
||||
expected []byte
|
||||
}{
|
||||
{128, []byte{0, 129}}, // 128 = 0 + 1*128
|
||||
{129, []byte{1, 129}}, // 129 = 1 + 1*128
|
||||
{255, []byte{127, 129}}, // 255 = 127 + 1*128
|
||||
{256, []byte{0, 130}}, // 256 = 0 + 2*128
|
||||
{16383, []byte{127, 255}}, // 16383 = 127 + 127*128
|
||||
{16384, []byte{0, 0, 129}}, // 16384 = 0 + 0*128 + 1*128*128
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(fmt.Sprintf("value_%d", tt.value), func(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
Encode(buf, tt.value)
|
||||
encoded := buf.Bytes()
|
||||
|
||||
if !bytes.Equal(encoded, tt.expected) {
|
||||
t.Errorf("Value %d: expected %v, got %v", tt.value, tt.expected, encoded)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode_ValidInputs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
expected uint64
|
||||
}{
|
||||
{"single_byte_zero", []byte{128}, 0},
|
||||
{"single_byte_one", []byte{129}, 1},
|
||||
{"single_byte_max", []byte{255}, 127},
|
||||
{"two_byte_128", []byte{0, 129}, 128},
|
||||
{"two_byte_255", []byte{127, 129}, 255},
|
||||
{"three_byte_16384", []byte{0, 0, 129}, 16384},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
decoded, err := Decode(bytes.NewBuffer(tt.input))
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if decoded != tt.expected {
|
||||
t.Errorf("Expected %d, got %d", tt.expected, decoded)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_WriteError(t *testing.T) {
|
||||
// Test with a writer that always fails
|
||||
failWriter := &failingWriter{}
|
||||
|
||||
// This should not panic even if write fails
|
||||
// The current implementation ignores write errors with _, _
|
||||
Encode(failWriter, 123)
|
||||
}
|
||||
|
||||
// Helper type for testing write failures
|
||||
type failingWriter struct{}
|
||||
|
||||
func (fw *failingWriter) Write(p []byte) (n int, err error) {
|
||||
return 0, io.ErrShortWrite
|
||||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
buf := new(bytes.Buffer)
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf.Reset()
|
||||
Encode(buf, uint64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecode(b *testing.B) {
|
||||
// Pre-encode a value
|
||||
buf := new(bytes.Buffer)
|
||||
Encode(buf, 12345)
|
||||
encoded := buf.Bytes()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = Decode(bytes.NewBuffer(encoded))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user