package pdu import ( "bytes" "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, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } if buf.Cap() != 16 { t.Errorf("Expected byte slice of length 16, got %d", buf.Cap()) } } func TestEncodeHandlesZeroValues(t *testing.T) { p := &PDU_HEADER{ command_length: 0, command_id: 0, command_status: 0, sequence_number: 0, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } expected := make([]byte, 16) for i, v := range buf.Bytes() { if v != expected[i] { t.Errorf("Expected byte slice with zero values, got %v", buf.Bytes()) break } } } func TestEncodeEncodesProperly(t *testing.T) { p := &PDU_HEADER{ command_length: 1, command_id: 2, command_status: 3, sequence_number: 4, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } expected := []byte{0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4} for i, v := range buf.Bytes() { if v != expected[i] { t.Errorf("Expected byte slice with values %v, got %v", expected, buf.Bytes()) break } } } func TestEncodeEncodesProperlyComplex(t *testing.T) { p := &PDU_HEADER{ command_length: 13426724, command_id: 254352, command_status: 35634264, sequence_number: 476543523, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } expected := []byte{0, 204, 224, 36, 0, 3, 225, 144, 2, 31, 188, 88, 28, 103, 122, 35} for i, v := range buf.Bytes() { if v != expected[i] { t.Errorf("Expected byte slice with values %v, got %v", expected, buf.Bytes()) break } } } func TestEncodeIntoCorrectlyEncodesFields(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } innerbuf := buf.Bytes() if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4])) } if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8])) } if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12])) } if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16])) } } func TestEncodeIntoHandlesLargerBuffer(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := bytes.NewBuffer(make([]byte, 20)) // larger buffer size buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } innerbuf := buf.Bytes() if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4])) } if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8])) } if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12])) } if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16])) } } func TestEncodeIntoUsesBigEndianEncoding(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } innerbuf := buf.Bytes() if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4])) } if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8])) } if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12])) } if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16])) } } func TestEncodeIntoConcurrencySafety(t *testing.T) { p := &PDU_HEADER{ command_length: 16, command_id: 1, command_status: 0, sequence_number: 12345, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() p.Encode(buf) }() } wg.Wait() innerbuf := buf.Bytes() if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4])) } if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8])) } if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12])) } if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[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 := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } innerbuf := buf.Bytes() if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4])) } if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8])) } if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12])) } if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16])) } } func TestEncodeIntoWithBoundaryValues(t *testing.T) { p := &PDU_HEADER{ command_length: 0, command_id: 0, command_status: 0, sequence_number: 0, } buf := bytes.NewBuffer(make([]byte, 16)) buf.Reset() err := p.Encode(buf) if err != nil { t.Errorf("Expected no error, got %v", err) } innerbuf := buf.Bytes() if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length { t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4])) } if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id { t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8])) } if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status { t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12])) } if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number { t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16])) } } // func TestRealScenario(t *testing.T) { // expected := []byte{0, 0, 0, 54, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 67, 77, 84, 0, 1, 1, 49, 50, 51, 52, 53, 0, 1, 1, 54, 55, 56, 57, 48, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 72, 101, 108, 108, 111, 44, 32, 83, 77, 80, 80, 33} // p := &SUBMIT_SM{ // header: PDU_HEADER{ // command_length: 0, // command_id: 4, // command_status: 0, // sequence_number: 1, // }, // service_type: "CMT", // source_addr_ton: 1, // source_addr_npi: 1, // source_addr: "12345", // dest_addr_ton: 1, // dest_addr_npi: 1, // destination_addr: "67890", // esm_class: 0, // protocol_id: 0, // priority_flag: 0, // schedule_delivery_time: "", // validity_period: "", // registered_delivery: 1, // data_coding: 0, // sm_default_msg_id: 0, // short_message: "Hello, SMPP!", // } // p.header.command_length = uint32(p.Size()) // p.sm_length = byte(len(p.short_message)) // buf := make([]byte, p.Size()) // err := p.EncodeInto(&buf) // if err != nil { // t.Errorf("Expected no error, got %v", err) // } // if len(buf) != len(expected) { // t.Errorf("Expected byte slice of length %d, got %d", len(expected), len(buf)) // } // for i, v := range buf { // if v != expected[i] { // t.Errorf("Expected byte slice with values %v, got %v", expected, buf) // break // } // } // } // // region decode // func TestDecodeHandlesShortByteSlice(t *testing.T) { // var p PDU_HEADER // data := []byte{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 := []byte{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([]byte, 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 := []byte{} // 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 := []byte{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3} // originalData := make([]byte, 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 := []byte{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 := []byte{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 BenchmarkEncodeWithBufferPool(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 := ByteBufferPool.Get(p.Size()) p.Encode(buf) ByteBufferPool.Put(buf) } } // Without buffer pool func BenchmarkEncodeWithoutBufferPool(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 := bytes.Buffer{} p.Encode(&buf) } } func BenchmarkDecodeBufferPool(b *testing.B) { p := &PDU_HEADER{} b.ResetTimer() for i := 0; i < b.N; i++ { data := []byte{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3} buf := ByteBufferPool.Get(len(data)) buf.Write(data) p.Decode(buf) ByteBufferPool.Put(buf) } }