package router import ( "bytes" "io" "math" "sync" "testing" ) // --------------------------------------------------------------------------- // packetConn tests // --------------------------------------------------------------------------- func TestPacketConn_ReadWrite(t *testing.T) { var buf bytes.Buffer pc := &packetConn{&fakeConn{writeBuf: buf}} // Write via packetConn's Write method n, err := pc.Write([]byte("hello")) if err != nil { t.Fatalf("Write: %v", err) } // packetConn.Write writes 2 bytes length-prefix + data, so n is the // total bytes written to the underlying conn. if n != 7 { t.Errorf("n = %d, want 7 (2-byte header + 5-byte payload)", n) } } func TestPacketConn_Write_ExceedsMaxUint16(t *testing.T) { pc := &packetConn{&fakeConn{}} large := make([]byte, math.MaxUint16+1) _, err := pc.Write(large) if err == nil { t.Error("Write: expected error for data exceeding MaxUint16") } } // --------------------------------------------------------------------------- // lockWriter tests // --------------------------------------------------------------------------- func TestLockWriter_Write(t *testing.T) { var buf bytes.Buffer lw := LockWriter(&buf) n, err := lw.Write([]byte("hello")) if err != nil { t.Fatalf("Write: %v", err) } if n != 5 { t.Errorf("n = %d, want 5", n) } if buf.String() != "hello" { t.Errorf("buf = %q, want hello", buf.String()) } } func TestLockWriter_Concurrent(t *testing.T) { var buf bytes.Buffer lw := LockWriter(&buf) var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() lw.Write([]byte("x")) }() } wg.Wait() if buf.Len() != 10 { t.Errorf("buf.Len = %d, want 10", buf.Len()) } } func TestLockWriter_Close_Closer(t *testing.T) { closed := false lw := LockWriter(&closeWriter{ closeFn: func() error { closed = true; return nil }, }) if err := lw.(io.Closer).Close(); err != nil { t.Fatalf("Close: %v", err) } if !closed { t.Error("underlying writer was not closed") } } func TestLockWriter_Close_NonCloser(t *testing.T) { // bytes.Buffer does NOT implement io.Closer var buf bytes.Buffer lw := LockWriter(&buf) if err := lw.(io.Closer).Close(); err != nil { t.Fatalf("Close: %v", err) } } func TestLockWriter_Close_Multiple(t *testing.T) { callCount := 0 lw := LockWriter(&closeWriter{ closeFn: func() error { callCount++; return nil }, }) lw.(io.Closer).Close() lw.(io.Closer).Close() // Close should be called each time since lockWriter.Close delegates // to the underlying closer without tracking. if callCount != 2 { t.Errorf("close called %d times, want 2", callCount) } } func TestLockWriter_WriteAfterClose(t *testing.T) { var buf bytes.Buffer lw := LockWriter(&buf) lw.(io.Closer).Close() // Write should still work after close (lockWriter doesn't track closed state) n, err := lw.Write([]byte("data")) if err != nil { t.Fatalf("Write after close: %v", err) } if n != 4 { t.Errorf("n = %d, want 4", n) } } // --------------------------------------------------------------------------- // LockWriter function tests // --------------------------------------------------------------------------- func TestLockWriter_NilWriter(t *testing.T) { lw := LockWriter(nil) if lw == nil { t.Fatal("LockWriter(nil) returned nil") } // Writing through a lockWriter with a nil underlying writer will panic. defer func() { if r := recover(); r == nil { t.Error("Write to nil writer should panic") } }() lw.Write([]byte("data")) } // --------------------------------------------------------------------------- // packetConn Round-trip test using pipeConn // --------------------------------------------------------------------------- func TestPacketConn_RoundTrip(t *testing.T) { a, b := newPipePair() defer a.Close() defer b.Close() pcA := &packetConn{a} pcB := &packetConn{b} // Write through pcA data := []byte("hello world") n, err := pcA.Write(data) if err != nil { t.Fatalf("Write: %v", err) } if n != len(data) { t.Errorf("n = %d, want %d", n, len(data)) } // Read through pcB readBuf := make([]byte, 1024) nr, err := pcB.Read(readBuf) if err != nil { t.Fatalf("Read: %v", err) } if nr != len(data) { t.Errorf("nr = %d, want %d", nr, len(data)) } if string(readBuf[:nr]) != string(data) { t.Errorf("Read = %q, want %q", string(readBuf[:nr]), string(data)) } } func TestPacketConn_Read_Empty(t *testing.T) { a, b := newPipePair() defer a.Close() defer b.Close() pcA := &packetConn{a} pcB := &packetConn{b} // Write empty data n, err := pcA.Write([]byte{}) if err != nil { t.Fatalf("Write empty: %v", err) } if n != 0 { t.Errorf("n = %d, want 0", n) } // Read should get 0 bytes readBuf := make([]byte, 1024) nr, err := pcB.Read(readBuf) if err != nil { t.Fatalf("Read: %v", err) } if nr != 0 { t.Errorf("nr = %d, want 0", nr) } } func TestPacketConn_Read_BufferSmaller(t *testing.T) { a, b := newPipePair() defer a.Close() defer b.Close() pcA := &packetConn{a} pcB := &packetConn{b} // Write data larger than read buffer data := []byte("this is a long message for testing") pcA.Write(data) // Read with small buffer readBuf := make([]byte, 5) nr, err := pcB.Read(readBuf) if err != nil { t.Fatalf("Read: %v", err) } if nr != 5 { t.Errorf("nr = %d, want 5", nr) } if string(readBuf[:nr]) != "this " { t.Errorf("Read = %q, want %q", string(readBuf[:nr]), "this ") } } func TestPacketConn_Read_EOF(t *testing.T) { a, b := newPipePair() a.Close() // Close write end so b gets EOF pcB := &packetConn{b} readBuf := make([]byte, 1024) _, err := pcB.Read(readBuf) if err != io.EOF { t.Errorf("Read = %v, want EOF", err) } }