ebml-go/value_test.go
2024-09-18 18:10:46 +02:00

429 lines
15 KiB
Go

package ebml
import (
"bytes"
"io"
"reflect"
"testing"
"time"
"git.gammaspectra.live/WeebDataHoarder/ebml-go/internal/errs"
)
func TestDataSize(t *testing.T) {
testCases := map[string]struct {
b []byte
i uint64
}{
"1 byte (upper bound)": {[]byte{0xFE}, 0x80 - 2},
"2 bytes (lower bound)": {[]byte{0x40, 0x7F}, 0x80 - 1},
"2 bytes (upper bound)": {[]byte{0x7F, 0xFE}, 0x4000 - 2},
"3 bytes (lower bound)": {[]byte{0x20, 0x3F, 0xFF}, 0x4000 - 1},
"3 bytes (upper bound)": {[]byte{0x3F, 0xFF, 0xFE}, 0x200000 - 2},
"4 bytes (lower bound)": {[]byte{0x10, 0x1F, 0xFF, 0xFF}, 0x200000 - 1},
"4 bytes (upper bound)": {[]byte{0x1F, 0xFF, 0xFF, 0xFE}, 0x10000000 - 2},
"5 bytes (lower bound)": {[]byte{0x08, 0x0F, 0xFF, 0xFF, 0xFF}, 0x10000000 - 1},
"5 bytes (upper bound)": {[]byte{0x0F, 0xFF, 0xFF, 0xFF, 0xFE}, 0x800000000 - 2},
"6 bytes (lower bound)": {[]byte{0x04, 0x07, 0xFF, 0xFF, 0xFF, 0xFF}, 0x800000000 - 1},
"6 bytes (upper bound)": {[]byte{0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 0x40000000000 - 2},
"7 bytes (lower bound)": {[]byte{0x02, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0x40000000000 - 1},
"7 bytes (upper bound)": {[]byte{0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 0x2000000000000 - 2},
"8 bytes (lower bound)": {[]byte{0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0x2000000000000 - 1},
"8 bytes (upper bound)": {[]byte{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 0xffffffffffffff - 1},
"Indefinite": {[]byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, SizeUnknown},
}
vd := &valueDecoder{}
for n, c := range testCases {
t.Run("DecodeVInt "+n, func(t *testing.T) {
r, _, err := vd.readVUInt(bytes.NewBuffer(c.b))
if err != nil {
t.Fatalf("Failed to readVUInt: '%v'", err)
}
if r != c.i {
t.Errorf("Expected readVUInt result: %d, got: %d", c.i, r)
}
})
}
for n, c := range testCases {
t.Run("DecodeDataSize "+n, func(t *testing.T) {
r, _, err := vd.readDataSize(bytes.NewBuffer(c.b))
if err != nil {
t.Fatalf("Failed to readDataSize: '%v'", err)
}
if r != c.i {
t.Errorf("Expected readVUInt result: %d, got: %d", c.i, r)
}
})
}
for n, c := range testCases {
t.Run("Encode "+n, func(t *testing.T) {
b := encodeDataSize(c.i, 0)
if !bytes.Equal(b, c.b) {
t.Errorf("Expected encodeDataSize result: %d, got: %d", c.b, b)
}
})
}
}
func TestDataSize_Unknown(t *testing.T) {
testCases := map[string][]byte{
"1 byte": {0xFF},
"2 bytes": {0x7F, 0xFF},
"3 bytes": {0x3F, 0xFF, 0xFF},
"4 bytes": {0x1F, 0xFF, 0xFF, 0xFF},
"5 bytes": {0x0F, 0xFF, 0xFF, 0xFF, 0xFF},
"6 bytes": {0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
"7 bytes": {0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
"8 bytes": {0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
}
vd := &valueDecoder{}
for n, b := range testCases {
t.Run("DecodeDataSize "+n, func(t *testing.T) {
r, _, err := vd.readDataSize(bytes.NewBuffer(b))
if err != nil {
t.Fatalf("Failed to readDataSize: '%v'", err)
}
if r != SizeUnknown {
t.Errorf("Expected readDataSize result: %d, got: %d", SizeUnknown, r)
}
})
}
}
func TestElementID(t *testing.T) {
testCases := map[string]struct {
b []byte
i uint64
}{
"1 byte (upper bound)": {[]byte{0xFF}, 0x80 - 1},
"2 bytes (lower bound)": {[]byte{0x40, 0x80}, 0x80},
"2 bytes (upper bound)": {[]byte{0x7F, 0xFF}, 0x4000 - 1},
"3 bytes (lower bound)": {[]byte{0x20, 0x40, 0x00}, 0x4000},
"3 bytes (upper bound)": {[]byte{0x3F, 0xFF, 0xFF}, 0x200000 - 1},
"4 bytes (lower bound)": {[]byte{0x10, 0x20, 0x00, 0x00}, 0x200000},
"4 bytes (upper bound)": {[]byte{0x1F, 0xFF, 0xFF, 0xFF}, 0x10000000 - 1},
"5 bytes (lower bound)": {[]byte{0x08, 0x10, 0x00, 0x00, 0x00}, 0x10000000},
"5 bytes (upper bound)": {[]byte{0x0F, 0xFF, 0xFF, 0xFF, 0xFF}, 0x800000000 - 1},
"6 bytes (lower bound)": {[]byte{0x04, 0x08, 0x00, 0x00, 0x00, 0x00}, 0x800000000},
"6 bytes (upper bound)": {[]byte{0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0x40000000000 - 1},
"7 bytes (lower bound)": {[]byte{0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x40000000000},
"7 bytes (upper bound)": {[]byte{0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0x2000000000000 - 1},
}
vd := &valueDecoder{}
for n, c := range testCases {
t.Run("Decode "+n, func(t *testing.T) {
r, _, err := vd.readVUInt(bytes.NewBuffer(c.b))
if err != nil {
t.Fatalf("Failed to readVUInt: '%v'", err)
}
if r != c.i {
t.Errorf("Expected readVUInt result: %d, got: %d", c.i, r)
}
})
}
for n, c := range testCases {
t.Run("Encode "+n, func(t *testing.T) {
b, err := encodeElementID(c.i)
if err != nil {
t.Fatalf("Failed to encodeElementID: '%v'", err)
}
if !bytes.Equal(b, c.b) {
t.Errorf("Expected encodeDataSize result: %d, got: %d", c.b, b)
}
})
}
_, err := encodeElementID(0x2000000000000)
if err != ErrUnsupportedElementID {
t.Errorf("Expected error type result: %s, got: %s", ErrUnsupportedElementID, err)
}
}
func TestVInt(t *testing.T) {
testCases := map[string]struct {
b []byte
i int64
}{
"1 byte (lower bound)": {[]byte{0x80}, -0x3F},
"1 byte (upper bound)": {[]byte{0xFE}, 0x3F},
"2 bytes (lower bound)": {[]byte{0x40, 0x00}, -0x1FFF},
"2 bytes (upper bound)": {[]byte{0x7F, 0xFE}, 0x1FFF},
"3 bytes (lower bound)": {[]byte{0x20, 0x00, 0x00}, -0xFFFFF},
"3 bytes (upper bound)": {[]byte{0x3F, 0xFF, 0xFE}, 0xFFFFF},
"4 bytes (lower bound)": {[]byte{0x10, 0x00, 0x00, 0x00}, -0x7FFFFFF},
"4 bytes (upper bound)": {[]byte{0x1F, 0xFF, 0xFF, 0xFE}, 0x7FFFFFF},
"5 bytes (lower bound)": {[]byte{0x08, 0x00, 0x00, 0x00, 0x00}, -0x3FFFFFFFF},
"5 bytes (upper bound)": {[]byte{0x0F, 0xFF, 0xFF, 0xFF, 0xFE}, 0x3FFFFFFFF},
"6 bytes (lower bound)": {[]byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, -0x1FFFFFFFFFF},
"6 bytes (upper bound)": {[]byte{0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 0x1FFFFFFFFFF},
"7 bytes (lower bound)": {[]byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -0xFFFFFFFFFFFF},
"7 bytes (upper bound)": {[]byte{0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 0xFFFFFFFFFFFF},
"8 bytes (lower bound)": {[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -0x7FFFFFFFFFFFFF},
"8 bytes (upper bound)": {[]byte{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 0x7FFFFFFFFFFFFF},
}
vd := &valueDecoder{}
for n, c := range testCases {
t.Run("Decode "+n, func(t *testing.T) {
r, _, err := vd.readVInt(bytes.NewBuffer(c.b))
if err != nil {
t.Fatalf("Failed to readVUInt: '%v'", err)
}
if r != c.i {
t.Errorf("Expected readVUInt result: %d, got: %d", c.i, r)
}
})
}
for n, c := range testCases {
t.Run("Encode "+n, func(t *testing.T) {
b, err := encodeVInt(c.i)
if err != nil {
t.Fatalf("Failed to encodeVInt: '%v'", err)
}
if !bytes.Equal(b, c.b) {
t.Errorf("Expected encodeVInt result: %d, got: %d", c.b, b)
}
})
}
}
func TestValue(t *testing.T) {
testCases := map[string]struct {
b []byte
t DataType
v interface{}
n uint64
vEnc interface{}
}{
"Binary": {[]byte{0x01, 0x02, 0x03}, DataTypeBinary, []byte{0x01, 0x02, 0x03}, 0, nil},
"Binary(4B)": {[]byte{0x01, 0x02, 0x03, 0x00}, DataTypeBinary, []byte{0x01, 0x02, 0x03, 0x00}, 4, []byte{0x01, 0x02, 0x03}},
"String": {[]byte{0x31, 0x32}, DataTypeString, "12", 0, nil},
"String(3B)": {[]byte{0x31, 0x32, 0x00}, DataTypeString, "12", 3, nil},
"String(4B)": {[]byte{0x31, 0x32, 0x00, 0x00}, DataTypeString, "12", 4, nil},
"Int8": {[]byte{0x01}, DataTypeInt, int64(0x01), 0, nil},
"Int16": {[]byte{0x01, 0x02}, DataTypeInt, int64(0x0102), 0, nil},
"Int24": {[]byte{0x01, 0x02, 0x03}, DataTypeInt, int64(0x010203), 0, nil},
"Int32": {[]byte{0x01, 0x02, 0x03, 0x04}, DataTypeInt, int64(0x01020304), 0, nil},
"Int40": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05}, DataTypeInt, int64(0x0102030405), 0, nil},
"Int48": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, DataTypeInt, int64(0x010203040506), 0, nil},
"Int56": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, DataTypeInt, int64(0x01020304050607), 0, nil},
"Int64": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, DataTypeInt, int64(0x0102030405060708), 0, nil},
"Int8(1B)": {[]byte{0x01}, DataTypeInt, int64(0x01), 1, nil},
"Int16(2B)": {[]byte{0x01, 0x02}, DataTypeInt, int64(0x0102), 2, nil},
"Int24(3B)": {[]byte{0x01, 0x02, 0x03}, DataTypeInt, int64(0x010203), 3, nil},
"Int32(4B)": {[]byte{0x01, 0x02, 0x03, 0x04}, DataTypeInt, int64(0x01020304), 4, nil},
"Int40(5B)": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05}, DataTypeInt, int64(0x0102030405), 5, nil},
"Int48(6B)": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, DataTypeInt, int64(0x010203040506), 6, nil},
"Int56(7B)": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, DataTypeInt, int64(0x01020304050607), 7, nil},
"Int64(8B)": {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, DataTypeInt, int64(0x0102030405060708), 8, nil},
"Int8(2B)": {[]byte{0x00, 0x01}, DataTypeInt, int64(0x01), 2, nil},
"Int16(3B)": {[]byte{0x00, 0x01, 0x02}, DataTypeInt, int64(0x0102), 3, nil},
"Int24(4B)": {[]byte{0x00, 0x01, 0x02, 0x03}, DataTypeInt, int64(0x010203), 4, nil},
"Int32(5B)": {[]byte{0x00, 0x01, 0x02, 0x03, 0x04}, DataTypeInt, int64(0x01020304), 5, nil},
"Int40(6B)": {[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, DataTypeInt, int64(0x0102030405), 6, nil},
"Int48(7B)": {[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, DataTypeInt, int64(0x010203040506), 7, nil},
"Int56(8B)": {[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 07}, DataTypeInt, int64(0x01020304050607), 8, nil},
"UInt": {[]byte{0x01, 0x02, 0x03}, DataTypeUInt, uint64(0x010203), 0, nil},
"Date": {[]byte{0x01, 0x02, 0x03}, DataTypeDate, time.Unix(DateEpochInUnixtime, 0x010203), 0, nil},
"Float32": {[]byte{0x40, 0x10, 0x00, 0x00}, DataTypeFloat, float64(2.25), 0, float32(2.25)},
"Float64": {[]byte{0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DataTypeFloat, float64(2.25), 0, nil},
"Float32(8B)": {[]byte{0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DataTypeFloat, float64(2.25), 8, float32(2.25)},
"Float64(4B)": {[]byte{0x40, 0x10, 0x00, 0x00}, DataTypeFloat, float64(2.25), 4, float64(2.25)},
"Float32(4B)": {[]byte{0x40, 0x10, 0x00, 0x00}, DataTypeFloat, float64(2.25), 4, float32(2.25)},
"Float64(8B)": {[]byte{0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DataTypeFloat, float64(2.25), 8, nil},
"Block": {[]byte{0x85, 0x12, 0x34, 0x80, 0x34, 0x56}, DataTypeBlock,
Block{uint64(5), int16(0x1234), true, false, LacingNo, false, [][]byte{{0x34, 0x56}}}, 0, nil,
},
"ConvertInt8": {[]byte{0x01}, DataTypeInt, int64(0x01), 0, int8(0x01)},
"ConvertInt16": {[]byte{0x01, 0x02}, DataTypeInt, int64(0x0102), 0, int16(0x0102)},
"ConvertInt32": {[]byte{0x01, 0x02, 0x03, 0x04}, DataTypeInt, int64(0x01020304), 0, int32(0x01020304)},
"ConvertInt": {[]byte{0x01, 0x02, 0x03, 0x04}, DataTypeInt, int64(0x01020304), 0, int(0x01020304)},
"ConvertUInt8": {[]byte{0x01}, DataTypeUInt, uint64(0x01), 0, uint8(0x01)},
"ConvertUInt16": {[]byte{0x01, 0x02}, DataTypeUInt, uint64(0x0102), 0, uint16(0x0102)},
"ConvertUInt32": {[]byte{0x01, 0x02, 0x03, 0x04}, DataTypeUInt, uint64(0x01020304), 0, uint32(0x01020304)},
"ConvertUInt": {[]byte{0x01, 0x02, 0x03, 0x04}, DataTypeUInt, uint64(0x01020304), 0, uint(0x01020304)},
}
vd := &valueDecoder{}
for n, c := range testCases {
t.Run("Read "+n, func(t *testing.T) {
v, err := vd.decode(c.t, bytes.NewBuffer(c.b), uint64(len(c.b)))
if err != nil {
t.Fatalf("Failed to read%s: '%v'", n, err)
}
if !reflect.DeepEqual(v, c.v) {
t.Errorf("Expected read%s result: %v, got: %v", n, c.v, v)
}
})
t.Run("Encode "+n, func(t *testing.T) {
var v interface{}
if c.vEnc != nil {
v = c.vEnc
} else {
v = c.v
}
b, err := perTypeEncoder[c.t](v, c.n)
if err != nil {
t.Fatalf("Failed to encode%s: '%v'", n, err)
}
if !bytes.Equal(b, c.b) {
t.Errorf("Expected encode%s result: %v, got: %v", n, c.b, b)
}
})
}
}
func TestEncodeValue_WrongInputType(t *testing.T) {
testCases := []struct {
t DataType
v []interface{}
err error
}{
{
DataTypeBinary,
[]interface{}{"aaa", int64(1), uint64(1), time.Unix(1, 0), float32(1.0), float64(1.0), Block{}},
ErrInvalidType,
},
{
DataTypeString,
[]interface{}{[]byte{0x01}, int64(1), uint64(1), time.Unix(1, 0), float32(1.0), float64(1.0), Block{}},
ErrInvalidType,
},
{
DataTypeInt,
[]interface{}{"aaa", []byte{0x01}, uint64(1), time.Unix(1, 0), float32(1.0), float64(1.0), Block{}},
ErrInvalidType,
},
{
DataTypeUInt,
[]interface{}{"aaa", []byte{0x01}, int64(1), time.Unix(1, 0), float32(1.0), float64(1.0), Block{}},
ErrInvalidType,
},
{
DataTypeDate,
[]interface{}{"aaa", []byte{0x01}, int64(1), uint64(1), float32(1.0), float64(1.0), Block{}},
ErrInvalidType,
},
{
DataTypeFloat,
[]interface{}{"aaa", []byte{0x01}, int64(1), uint64(1), time.Unix(1, 0), Block{}},
ErrInvalidType,
},
{
DataTypeBlock,
[]interface{}{"aaa", []byte{0x01}, int64(1), uint64(1), time.Unix(1, 0), float32(1.0), float64(1.0)},
ErrInvalidType,
},
}
for _, c := range testCases {
t.Run("Encode "+c.t.String(), func(t *testing.T) {
for _, v := range c.v {
_, err := perTypeEncoder[c.t](v, 0)
if !errs.Is(err, c.err) {
t.Fatalf("Expected error against wrong input type %s: '%v, got: '%v'", c.t.String(), c.err, err)
}
}
})
}
}
func TestEncodeValue_WrongSize(t *testing.T) {
testCases := map[string]struct {
t DataType
v interface{}
n uint64
err error
}{
"Float32(3B)": {
DataTypeFloat,
float32(1.0),
3,
ErrInvalidFloatSize,
},
"Float64(9B)": {
DataTypeFloat,
float64(1.0),
9,
ErrInvalidFloatSize,
},
}
for n, c := range testCases {
t.Run("Encode "+n, func(t *testing.T) {
_, err := perTypeEncoder[c.t](c.v, c.n)
if !errs.Is(err, c.err) {
t.Fatalf("Expected error against wrong input type %s: '%v', got: '%v'", n, c.err, err)
}
})
}
}
func TestEncodeValue_OutOfRange(t *testing.T) {
_, err := encodeVInt(1<<63 - 1)
if err != ErrOutOfRange {
t.Fatalf("Expected error: '%v', got: '%v'", ErrOutOfRange, err)
}
}
func TestReadValue_WrongSize(t *testing.T) {
testCases := map[string]struct {
t DataType
b []byte
n uint64
err error
}{
"Float32(3B)": {
DataTypeFloat,
[]byte{0, 0, 0},
3,
ErrInvalidFloatSize,
},
}
vd := &valueDecoder{}
for n, c := range testCases {
t.Run("Read "+n, func(t *testing.T) {
_, err := vd.decode(c.t, bytes.NewReader(c.b), c.n)
if !errs.Is(err, c.err) {
t.Fatalf("Expected error against wrong data size of %s: %v, got: %v", n, c.err, err)
}
})
}
}
func TestReadValue_ReadUnexpectedEOF(t *testing.T) {
testCases := []struct {
t DataType
b []byte
}{
{DataTypeBinary, []byte{0x00, 0x00}},
{DataTypeString, []byte{0x00, 0x00}},
{DataTypeInt, []byte{0x00, 0x00}},
{DataTypeUInt, []byte{0x00, 0x00}},
{DataTypeDate, []byte{0x00, 0x00}},
{DataTypeFloat, []byte{0x00, 0x00, 0x00, 0x00}},
}
vd := &valueDecoder{}
for _, c := range testCases {
t.Run("Read "+c.t.String(), func(t *testing.T) {
for l := 0; l < len(c.b)-1; l++ {
r := bytes.NewReader(c.b[:l])
_, err := vd.decode(c.t, r, uint64(len(c.b)))
if !errs.Is(err, io.ErrUnexpectedEOF) {
t.Errorf("Expected error against short (%d bytes) %s: %v, got: %v",
l, c.t.String(), io.ErrUnexpectedEOF, err)
}
}
})
}
}