mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
503 lines
11 KiB
Go
503 lines
11 KiB
Go
package byteframe
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"io"
|
|
"math"
|
|
"testing"
|
|
)
|
|
|
|
func TestNewByteFrame(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
if bf == nil {
|
|
t.Fatal("NewByteFrame() returned nil")
|
|
}
|
|
if bf.index != 0 {
|
|
t.Errorf("index = %d, want 0", bf.index)
|
|
}
|
|
if bf.usedSize != 0 {
|
|
t.Errorf("usedSize = %d, want 0", bf.usedSize)
|
|
}
|
|
if len(bf.buf) != 4 {
|
|
t.Errorf("buf length = %d, want 4", len(bf.buf))
|
|
}
|
|
if bf.byteOrder != binary.BigEndian {
|
|
t.Error("byteOrder should be BigEndian by default")
|
|
}
|
|
}
|
|
|
|
func TestNewByteFrameFromBytes(t *testing.T) {
|
|
input := []byte{0x01, 0x02, 0x03, 0x04}
|
|
bf := NewByteFrameFromBytes(input)
|
|
if bf == nil {
|
|
t.Fatal("NewByteFrameFromBytes() returned nil")
|
|
}
|
|
if bf.index != 0 {
|
|
t.Errorf("index = %d, want 0", bf.index)
|
|
}
|
|
if bf.usedSize != uint(len(input)) {
|
|
t.Errorf("usedSize = %d, want %d", bf.usedSize, len(input))
|
|
}
|
|
if !bytes.Equal(bf.buf, input) {
|
|
t.Errorf("buf = %v, want %v", bf.buf, input)
|
|
}
|
|
// Verify it's a copy, not the same slice
|
|
input[0] = 0xFF
|
|
if bf.buf[0] == 0xFF {
|
|
t.Error("NewByteFrameFromBytes should make a copy, not use the same slice")
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadUint8(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
values := []uint8{0, 1, 127, 128, 255}
|
|
|
|
for _, v := range values {
|
|
bf.WriteUint8(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadUint8()
|
|
if got != expected {
|
|
t.Errorf("ReadUint8()[%d] = %d, want %d", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadUint16(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value uint16
|
|
}{
|
|
{"zero", 0},
|
|
{"one", 1},
|
|
{"max_int8", 127},
|
|
{"max_uint8", 255},
|
|
{"max_int16", 32767},
|
|
{"max_uint16", 65535},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteUint16(tt.value)
|
|
bf.Seek(0, io.SeekStart)
|
|
got := bf.ReadUint16()
|
|
if got != tt.value {
|
|
t.Errorf("ReadUint16() = %d, want %d", got, tt.value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadUint32(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value uint32
|
|
}{
|
|
{"zero", 0},
|
|
{"one", 1},
|
|
{"max_uint16", 65535},
|
|
{"max_uint32", 4294967295},
|
|
{"arbitrary", 0x12345678},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteUint32(tt.value)
|
|
bf.Seek(0, io.SeekStart)
|
|
got := bf.ReadUint32()
|
|
if got != tt.value {
|
|
t.Errorf("ReadUint32() = %d, want %d", got, tt.value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadUint64(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value uint64
|
|
}{
|
|
{"zero", 0},
|
|
{"one", 1},
|
|
{"max_uint32", 4294967295},
|
|
{"max_uint64", 18446744073709551615},
|
|
{"arbitrary", 0x123456789ABCDEF0},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteUint64(tt.value)
|
|
bf.Seek(0, io.SeekStart)
|
|
got := bf.ReadUint64()
|
|
if got != tt.value {
|
|
t.Errorf("ReadUint64() = %d, want %d", got, tt.value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadInt8(t *testing.T) {
|
|
values := []int8{-128, -1, 0, 1, 127}
|
|
bf := NewByteFrame()
|
|
|
|
for _, v := range values {
|
|
bf.WriteInt8(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadInt8()
|
|
if got != expected {
|
|
t.Errorf("ReadInt8()[%d] = %d, want %d", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadInt16(t *testing.T) {
|
|
values := []int16{-32768, -1, 0, 1, 32767}
|
|
bf := NewByteFrame()
|
|
|
|
for _, v := range values {
|
|
bf.WriteInt16(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadInt16()
|
|
if got != expected {
|
|
t.Errorf("ReadInt16()[%d] = %d, want %d", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadInt32(t *testing.T) {
|
|
values := []int32{-2147483648, -1, 0, 1, 2147483647}
|
|
bf := NewByteFrame()
|
|
|
|
for _, v := range values {
|
|
bf.WriteInt32(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadInt32()
|
|
if got != expected {
|
|
t.Errorf("ReadInt32()[%d] = %d, want %d", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadInt64(t *testing.T) {
|
|
values := []int64{-9223372036854775808, -1, 0, 1, 9223372036854775807}
|
|
bf := NewByteFrame()
|
|
|
|
for _, v := range values {
|
|
bf.WriteInt64(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadInt64()
|
|
if got != expected {
|
|
t.Errorf("ReadInt64()[%d] = %d, want %d", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadFloat32(t *testing.T) {
|
|
values := []float32{0.0, -1.5, 1.5, 3.14159, math.MaxFloat32, -math.MaxFloat32}
|
|
bf := NewByteFrame()
|
|
|
|
for _, v := range values {
|
|
bf.WriteFloat32(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadFloat32()
|
|
if got != expected {
|
|
t.Errorf("ReadFloat32()[%d] = %f, want %f", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadFloat64(t *testing.T) {
|
|
values := []float64{0.0, -1.5, 1.5, 3.14159265358979, math.MaxFloat64, -math.MaxFloat64}
|
|
bf := NewByteFrame()
|
|
|
|
for _, v := range values {
|
|
bf.WriteFloat64(v)
|
|
}
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
for i, expected := range values {
|
|
got := bf.ReadFloat64()
|
|
if got != expected {
|
|
t.Errorf("ReadFloat64()[%d] = %f, want %f", i, got, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadBool(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteBool(true)
|
|
bf.WriteBool(false)
|
|
bf.WriteBool(true)
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
if got := bf.ReadBool(); got != true {
|
|
t.Errorf("ReadBool()[0] = %v, want true", got)
|
|
}
|
|
if got := bf.ReadBool(); got != false {
|
|
t.Errorf("ReadBool()[1] = %v, want false", got)
|
|
}
|
|
if got := bf.ReadBool(); got != true {
|
|
t.Errorf("ReadBool()[2] = %v, want true", got)
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadBytes(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
input := []byte{0x01, 0x02, 0x03, 0x04, 0x05}
|
|
bf.WriteBytes(input)
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
got := bf.ReadBytes(uint(len(input)))
|
|
if !bytes.Equal(got, input) {
|
|
t.Errorf("ReadBytes() = %v, want %v", got, input)
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_WriteAndReadNullTerminatedBytes(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
input := []byte("Hello, World!")
|
|
bf.WriteNullTerminatedBytes(input)
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
got := bf.ReadNullTerminatedBytes()
|
|
if !bytes.Equal(got, input) {
|
|
t.Errorf("ReadNullTerminatedBytes() = %v, want %v", got, input)
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_ReadNullTerminatedBytes_NoNull(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
input := []byte("Hello")
|
|
bf.WriteBytes(input)
|
|
|
|
bf.Seek(0, io.SeekStart)
|
|
got := bf.ReadNullTerminatedBytes()
|
|
// When there's no null terminator, it should return empty slice
|
|
if len(got) != 0 {
|
|
t.Errorf("ReadNullTerminatedBytes() = %v, want empty slice", got)
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_Endianness(t *testing.T) {
|
|
// Test BigEndian (default)
|
|
bfBE := NewByteFrame()
|
|
bfBE.WriteUint16(0x1234)
|
|
dataBE := bfBE.Data()
|
|
if dataBE[0] != 0x12 || dataBE[1] != 0x34 {
|
|
t.Errorf("BigEndian: got %X %X, want 12 34", dataBE[0], dataBE[1])
|
|
}
|
|
|
|
// Test LittleEndian
|
|
bfLE := NewByteFrame()
|
|
bfLE.SetLE()
|
|
bfLE.WriteUint16(0x1234)
|
|
dataLE := bfLE.Data()
|
|
if dataLE[0] != 0x34 || dataLE[1] != 0x12 {
|
|
t.Errorf("LittleEndian: got %X %X, want 34 12", dataLE[0], dataLE[1])
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_Seek(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteBytes([]byte{0x01, 0x02, 0x03, 0x04, 0x05})
|
|
|
|
tests := []struct {
|
|
name string
|
|
offset int64
|
|
whence int
|
|
wantIndex uint
|
|
wantErr bool
|
|
}{
|
|
{"seek_start_0", 0, io.SeekStart, 0, false},
|
|
{"seek_start_2", 2, io.SeekStart, 2, false},
|
|
{"seek_start_5", 5, io.SeekStart, 5, false},
|
|
{"seek_start_beyond", 6, io.SeekStart, 5, true},
|
|
{"seek_current_forward", 2, io.SeekCurrent, 5, true}, // Will go beyond max
|
|
{"seek_current_backward", -3, io.SeekCurrent, 2, false},
|
|
{"seek_current_before_start", -10, io.SeekCurrent, 2, true},
|
|
{"seek_end_0", 0, io.SeekEnd, 5, false},
|
|
{"seek_end_negative", -2, io.SeekEnd, 3, false},
|
|
{"seek_end_beyond", 1, io.SeekEnd, 3, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Reset to known position for each test
|
|
bf.Seek(5, io.SeekStart)
|
|
|
|
pos, err := bf.Seek(tt.offset, tt.whence)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Errorf("Seek() expected error, got nil")
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Seek() unexpected error: %v", err)
|
|
}
|
|
if bf.index != tt.wantIndex {
|
|
t.Errorf("index = %d, want %d", bf.index, tt.wantIndex)
|
|
}
|
|
if uint(pos) != tt.wantIndex {
|
|
t.Errorf("returned position = %d, want %d", pos, tt.wantIndex)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_Data(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
input := []byte{0x01, 0x02, 0x03, 0x04, 0x05}
|
|
bf.WriteBytes(input)
|
|
|
|
data := bf.Data()
|
|
if !bytes.Equal(data, input) {
|
|
t.Errorf("Data() = %v, want %v", data, input)
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_DataFromCurrent(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteBytes([]byte{0x01, 0x02, 0x03, 0x04, 0x05})
|
|
bf.Seek(2, io.SeekStart)
|
|
|
|
data := bf.DataFromCurrent()
|
|
expected := []byte{0x03, 0x04, 0x05}
|
|
if !bytes.Equal(data, expected) {
|
|
t.Errorf("DataFromCurrent() = %v, want %v", data, expected)
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_Index(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
if bf.Index() != 0 {
|
|
t.Errorf("Index() = %d, want 0", bf.Index())
|
|
}
|
|
|
|
bf.WriteUint8(0x01)
|
|
if bf.Index() != 1 {
|
|
t.Errorf("Index() = %d, want 1", bf.Index())
|
|
}
|
|
|
|
bf.WriteUint16(0x0102)
|
|
if bf.Index() != 3 {
|
|
t.Errorf("Index() = %d, want 3", bf.Index())
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_BufferGrowth(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
initialCap := len(bf.buf)
|
|
|
|
// Write enough data to force growth
|
|
for i := 0; i < 100; i++ {
|
|
bf.WriteUint32(uint32(i))
|
|
}
|
|
|
|
if len(bf.buf) <= initialCap {
|
|
t.Errorf("Buffer should have grown, initial cap: %d, current: %d", initialCap, len(bf.buf))
|
|
}
|
|
|
|
// Verify all data is still accessible
|
|
bf.Seek(0, io.SeekStart)
|
|
for i := 0; i < 100; i++ {
|
|
got := bf.ReadUint32()
|
|
if got != uint32(i) {
|
|
t.Errorf("After growth, ReadUint32()[%d] = %d, want %d", i, got, i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByteFrame_ReadPanic(t *testing.T) {
|
|
defer func() {
|
|
if r := recover(); r == nil {
|
|
t.Error("Reading beyond buffer should panic")
|
|
}
|
|
}()
|
|
|
|
bf := NewByteFrame()
|
|
bf.WriteUint8(0x01)
|
|
bf.Seek(0, io.SeekStart)
|
|
bf.ReadUint8()
|
|
bf.ReadUint16() // Should panic - trying to read 2 bytes when only 1 was written
|
|
}
|
|
|
|
func TestByteFrame_SequentialWrites(t *testing.T) {
|
|
bf := NewByteFrame()
|
|
bf.WriteUint8(0x01)
|
|
bf.WriteUint16(0x0203)
|
|
bf.WriteUint32(0x04050607)
|
|
bf.WriteUint64(0x08090A0B0C0D0E0F)
|
|
|
|
expected := []byte{
|
|
0x01, // uint8
|
|
0x02, 0x03, // uint16
|
|
0x04, 0x05, 0x06, 0x07, // uint32
|
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // uint64
|
|
}
|
|
|
|
data := bf.Data()
|
|
if !bytes.Equal(data, expected) {
|
|
t.Errorf("Sequential writes: got %X, want %X", data, expected)
|
|
}
|
|
}
|
|
|
|
func BenchmarkByteFrame_WriteUint8(b *testing.B) {
|
|
bf := NewByteFrame()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
bf.WriteUint8(0x42)
|
|
}
|
|
}
|
|
|
|
func BenchmarkByteFrame_WriteUint32(b *testing.B) {
|
|
bf := NewByteFrame()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
bf.WriteUint32(0x12345678)
|
|
}
|
|
}
|
|
|
|
func BenchmarkByteFrame_ReadUint32(b *testing.B) {
|
|
bf := NewByteFrame()
|
|
for i := 0; i < 1000; i++ {
|
|
bf.WriteUint32(0x12345678)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
bf.Seek(0, io.SeekStart)
|
|
bf.ReadUint32()
|
|
}
|
|
}
|
|
|
|
func BenchmarkByteFrame_WriteBytes(b *testing.B) {
|
|
bf := NewByteFrame()
|
|
data := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
bf.WriteBytes(data)
|
|
}
|
|
}
|