package pdu import ( "encoding/binary" "math" "sync" "testing" ) // region encode func TestEncodeReturnsByteSliceOfLength16(t *testing.T) { p := &PDU_HEADER{ command_length: 1, command_id: 1, command_status: 1, sequence_number: 1, } result, err := p.Encode() if err != nil { t.Errorf("Expected no error, got %v", err) } if len(*result) != 16 { t.Errorf("Expected byte slice of length 16, got %d", len(*result)) } } func TestEncodeHandlesZeroValues(t *testing.T) { p := &PDU_HEADER{ command_length: 0, command_id: 0, command_status: 0, sequence_number: 0, } result, err := p.Encode() if err != nil { t.Errorf("Expected no error, got %v", err) } expected := make([]uint8, 16) for i, v := range *result { if v != expected[i] { t.Errorf("Expected byte slice with zero values, got %v", *result) break } } } func TestEncodeEncodesProperly(t *testing.T) { p := &PDU_HEADER{ command_length: 1, command_id: 2, command_status: 3, sequence_number: 4, } result, err := p.Encode() if err != nil { t.Errorf("Expected no error, got %v", err) } expected := []uint8{0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4} for i, v := range *result { if v != expected[i] { t.Errorf("Expected byte slice with values %v, got %v", expected, *result) break } } } func TestEncodeEncodesProperlyComplex(t *testing.T) { p := &PDU_HEADER{ command_length: 13426724, command_id: 254352, command_status: 35634264, sequence_number: 476543523, } result, err := p.Encode() if err != nil { t.Errorf("Expected no error, got %v", err) } expected := []uint8{0, 204, 224, 36, 0, 3, 225, 144, 2, 31, 188, 88, 28, 103, 122, 35} for i, v := range *result { if v != expected[i] { t.Errorf("Expected byte slice with values %v, got %v", expected, *result) break } } } func TestEncodeIntoCorrectlyEncodesFields(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := make([]uint8, 16) err := p.EncodeInto(&buf) if err != nil { t.Errorf("Expected no error, got %v", err) } if binary.BigEndian.Uint32(buf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(buf[0:4])) } if binary.BigEndian.Uint32(buf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(buf[4:8])) } if binary.BigEndian.Uint32(buf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(buf[8:12])) } if binary.BigEndian.Uint32(buf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(buf[12:16])) } } func TestEncodeIntoHandlesNilBuffer(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } var buf *[]uint8 = nil err := p.EncodeInto(buf) if err == nil { t.Errorf("Expected error when buffer is nil") } } func TestEncodeIntoHandlesSmallerBuffer(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := make([]uint8, 12) // smaller buffer size err := p.EncodeInto(&buf) if err == nil { t.Errorf("Expected error when buffer is too small") } } func TestEncodeIntoHandlesLargerBuffer(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := make([]uint8, 20) err := p.EncodeInto(&buf) if err != nil { t.Errorf("Expected no error, got %v", err) } if binary.BigEndian.Uint32(buf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(buf[0:4])) } if binary.BigEndian.Uint32(buf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(buf[4:8])) } if binary.BigEndian.Uint32(buf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(buf[8:12])) } if binary.BigEndian.Uint32(buf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(buf[12:16])) } } func TestEncodeIntoUsesBigEndianEncoding(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := make([]uint8, 16) err := p.EncodeInto(&buf) if err != nil { t.Errorf("Expected no error, got %v", err) } if binary.BigEndian.Uint32(buf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(buf[0:4])) } if binary.BigEndian.Uint32(buf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(buf[4:8])) } if binary.BigEndian.Uint32(buf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(buf[8:12])) } if binary.BigEndian.Uint32(buf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(buf[12:16])) } } func TestEncodeIntoConcurrencySafety(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := make([]uint8, 16) var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() p.EncodeInto(&buf) }() } wg.Wait() if binary.BigEndian.Uint32(buf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(buf[0:4])) } if binary.BigEndian.Uint32(buf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(buf[4:8])) } if binary.BigEndian.Uint32(buf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(buf[8:12])) } if binary.BigEndian.Uint32(buf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(buf[12:16])) } } func TestEncodeIntoWithMaximumValues(t *testing.T) { p := &PDU_HEADER{ command_length: math.MaxUint32, command_id: math.MaxUint32, command_status: math.MaxUint32, sequence_number: math.MaxUint32, } buf := make([]uint8, 16) err := p.EncodeInto(&buf) if err != nil { t.Errorf("Expected no error, got %v", err) } if binary.BigEndian.Uint32(buf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(buf[0:4])) } if binary.BigEndian.Uint32(buf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(buf[4:8])) } if binary.BigEndian.Uint32(buf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(buf[8:12])) } if binary.BigEndian.Uint32(buf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(buf[12:16])) } } func TestEncodeIntoWithBoundaryValues(t *testing.T) { p := &PDU_HEADER{ command_length: 0, command_id: 0, command_status: 0, sequence_number: 0, } buf := make([]uint8, 16) err := p.EncodeInto(&buf) if err != nil { t.Errorf("Expected no error, got %v", err) } if binary.BigEndian.Uint32(buf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(buf[0:4])) } if binary.BigEndian.Uint32(buf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(buf[4:8])) } if binary.BigEndian.Uint32(buf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(buf[8:12])) } if binary.BigEndian.Uint32(buf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(buf[12:16])) } } // region decode func TestDecodeHandlesShortByteSlice(t *testing.T) { var p PDU_HEADER data := []uint8{0, 0, 0, 10} defer func() { if r := recover(); r != nil { t.Errorf("Decode panicked with short byte slice") } }() err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } } func TestDecodeParsesValidByteSlice(t *testing.T) { var p PDU_HEADER data := []uint8{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3} err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } if p.command_length != 16 { t.Errorf("Expected command_length to be 16, got %d", p.command_length) } if p.command_id != 1 { t.Errorf("Expected command_id to be 1, got %d", p.command_id) } if p.command_status != 2 { t.Errorf("Expected command_status to be 2, got %d", p.command_status) } if p.sequence_number != 3 { t.Errorf("Expected sequence_number to be 3, got %d", p.sequence_number) } } func TestDecodeHandlesLongerByteSliceWithoutCrashing(t *testing.T) { var p PDU_HEADER data := make([]uint8, 20) defer func() { if r := recover(); r != nil { t.Errorf("Decode panicked with long byte slice") } }() err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } } func TestDecodeHandlesNilDataInput(t *testing.T) { var p PDU_HEADER err := p.Decode(nil) if err != nil { t.Errorf("Expected no error, got %v", err) } if p.command_length != 0 { t.Errorf("Expected command_length to be 0, got %d", p.command_length) } if p.command_id != 0 { t.Errorf("Expected command_id to be 0, got %d", p.command_id) } if p.command_status != 0 { t.Errorf("Expected command_status to be 0, got %d", p.command_status) } if p.sequence_number != 0 { t.Errorf("Expected sequence_number to be 0, got %d", p.sequence_number) } } func TestDecodeHandlesEmptyByteSliceGracefully(t *testing.T) { var p PDU_HEADER data := []uint8{} err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } if p.command_length != 0 { t.Errorf("Expected command_length to be 0, got %d", p.command_length) } if p.command_id != 0 { t.Errorf("Expected command_id to be 0, got %d", p.command_id) } if p.command_status != 0 { t.Errorf("Expected command_status to be 0, got %d", p.command_status) } if p.sequence_number != 0 { t.Errorf("Expected sequence_number to be 0, got %d", p.sequence_number) } } func TestDecodeDoesNotModifyInputByteSlice(t *testing.T) { var p PDU_HEADER data := []uint8{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3} originalData := make([]uint8, len(data)) copy(originalData, data) err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } for i := range data { if data[i] != originalData[i] { t.Errorf("Expected data at index %d to be %d, got %d", i, originalData[i], data[i]) } } } func TestDecodeHandlesByteSlicesWithMaxUint32Values(t *testing.T) { var p PDU_HEADER data := []uint8{255, 255, 255, 255, 255, 255, 255, 255} err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } if p.command_length != math.MaxUint32 { t.Errorf("Expected command_length to be %d, got %d", math.MaxUint32, p.command_length) } if p.command_id != math.MaxUint32 { t.Errorf("Expected command_id to be %d, got %d", math.MaxUint32, p.command_id) } } func TestDecodeHandlesByteSlicesWithMinimumUint32Values(t *testing.T) { var p PDU_HEADER data := []uint8{0, 0, 0, 0, 0, 0, 0, 0} err := p.Decode(data) if err != nil { t.Errorf("Expected no error, got %v", err) } if p.command_length != 0 { t.Errorf("Expected command_length to be 0, got %d", p.command_length) } if p.command_id != 0 { t.Errorf("Expected command_id to be 0, got %d", p.command_id) } } // region size func TestSizeReturns16(t *testing.T) { var p PDU_HEADER if p.Size() != 16 { t.Errorf("Expected size to be 16, got %d", p.Size()) } } // region benchmarks // With buffer pool func BenchmarkEncode(b *testing.B) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } b.ResetTimer() for i := 0; i < b.N; i++ { p.Encode() } } // Without buffer pool func BenchmarkEncodeInto(b *testing.B) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } b.ResetTimer() for i := 0; i < b.N; i++ { buf := make([]uint8, 16) p.EncodeInto(&buf) } } func BenchmarkDecode(b *testing.B) { p := &PDU_HEADER{} data := []uint8{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3} b.ResetTimer() for i := 0; i < b.N; i++ { p.Decode(data) } }