Files
zogo/frame/frame_test.go
T
4566704 9d7a512e18 feat(frame): go-hua/common 帧协议独立成包并修复两处缺陷
- SetData 超长时 fmt.Errorf 结果未 return,超 65535 字节静默放行 → 改为返回错误
- ReadFrame 原实现 conn.Read 直读帧头(短读错位)且一次性 bufio.Reader 会丢弃
  缓冲中的后续帧字节 → 统一改 io.ReadFull 精确读取,新增连续两帧回归测试
- 补齐单元测试(往返/流水线/超长/Marshal/RawHeader)、examples/frame 例程与 README
2026-09-20 12:20:51 +08:00

111 lines
2.6 KiB
Go

package frame
import (
"encoding/binary"
"net"
"testing"
)
func TestFrameRoundtrip(t *testing.T) {
c1, c2 := net.Pipe()
defer c1.Close()
defer c2.Close()
f := NewFrame(FrameVersion, 0x10, 42)
if err := f.SetData([]byte("hello frame")); err != nil {
t.Fatalf("SetData: %v", err)
}
go func() {
if err := WriteFrame(c1, f); err != nil {
t.Errorf("WriteFrame: %v", err)
}
}()
got, err := ReadFrame(c2)
if err != nil {
t.Fatalf("ReadFrame: %v", err)
}
if got.Version() != FrameVersion || got.Cmd() != 0x10 || got.StreamID() != 42 {
t.Errorf("帧头不符: %s", got.String())
}
if string(got.Data()) != "hello frame" {
t.Errorf("Data = %q, want hello frame", got.Data())
}
}
func TestFramePipelineRead(t *testing.T) {
// 连续两帧不丢数据(回归:旧实现用临时 bufio.Reader 会吞掉后续帧字节)
c1, c2 := net.Pipe()
defer c1.Close()
defer c2.Close()
go func() {
a := NewFrame(1, 1, 1)
if err := a.SetData([]byte("first")); err != nil {
t.Errorf("SetData: %v", err)
}
b := NewFrame(1, 2, 2)
if err := b.SetData([]byte("second")); err != nil {
t.Errorf("SetData: %v", err)
}
if err := WriteFrame(c1, a); err != nil {
t.Errorf("WriteFrame: %v", err)
}
if err := WriteFrame(c1, b); err != nil {
t.Errorf("WriteFrame: %v", err)
}
}()
got1, err := ReadFrame(c2)
if err != nil || string(got1.Data()) != "first" {
t.Fatalf("第一帧 = %q, %v", got1.Data(), err)
}
got2, err := ReadFrame(c2)
if err != nil || string(got2.Data()) != "second" {
t.Fatalf("第二帧 = %q, %v", got2.Data(), err)
}
}
func TestSetDataOverflow(t *testing.T) {
f := NewFrame(1, 0, 0)
if err := f.SetData(make([]byte, 65536)); err == nil {
t.Error("超过 65535 字节应返回错误")
}
if err := f.SetData(make([]byte, 65535)); err != nil {
t.Errorf("65535 字节应成功: %v", err)
}
}
func TestMarshalUnmarshal(t *testing.T) {
f := NewFrame(1, 3, 9)
type payload struct {
Name string
N int
}
if err := f.Marshal(payload{Name: "a", N: 1}); err != nil {
t.Fatalf("Marshal: %v", err)
}
var got payload
if err := f.Unmarshal(&got); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if got.Name != "a" || got.N != 1 {
t.Errorf("Unmarshal 结果 = %+v", got)
}
}
func TestRawHeader(t *testing.T) {
h := RawHeader{}
h[0] = 2
h[1] = 7
binary.LittleEndian.PutUint16(h[2:], 300)
binary.LittleEndian.PutUint32(h[4:], 100000)
if h.Version() != 2 || h.Cmd() != 7 || h.Length() != 300 || h.StreamID() != 100000 {
t.Errorf("RawHeader 解析不符: %v %v %v %v", h.Version(), h.Cmd(), h.Length(), h.StreamID())
}
if len(h.Bytes()) != 8 {
t.Errorf("Bytes 长度 = %d, want 8", len(h.Bytes()))
}
}