Files
uopi/pkg/pva/proto_test.go
Martino Ferrari c0f7e662be Testing
2026-06-24 01:39:15 +02:00

176 lines
4.9 KiB
Go

package pva
import (
"bytes"
"encoding/binary"
"testing"
)
// ---- Header codec -----------------------------------------------------
func TestHeaderRoundTrip(t *testing.T) {
h := PVAHeader{Version: 1, Flags: flagApp, Command: CmdGet, Size: 1234}
var buf bytes.Buffer
if err := WriteHeader(&buf, h); err != nil {
t.Fatal(err)
}
got, err := ReadHeader(&buf)
if err != nil {
t.Fatal(err)
}
if got.Version != h.Version || got.Command != h.Command || got.Size != h.Size {
t.Errorf("round-trip header: got %+v want %+v", got, h)
}
}
func TestReadHeaderBadMagic(t *testing.T) {
raw := []byte{0xAB, 0x01, 0x00, CmdGet, 0, 0, 0, 0}
if _, err := ReadHeader(bytes.NewReader(raw)); err == nil {
t.Error("bad magic: want error")
}
}
func TestReadHeaderTruncated(t *testing.T) {
if _, err := ReadHeader(bytes.NewReader([]byte{0xCA, 0x01})); err == nil {
t.Error("truncated header: want error")
}
}
func TestHeaderBigEndian(t *testing.T) {
// Hand-assemble a big-endian server header with size 0x00010203.
raw := []byte{magic, 0x01, flagBigEndian | flagFromServer, CmdMonitor, 0x00, 0x01, 0x02, 0x03}
h, err := ReadHeader(bytes.NewReader(raw))
if err != nil {
t.Fatal(err)
}
if h.isLittleEndian() {
t.Error("expected big-endian header")
}
if !h.isFromServer() {
t.Error("expected from-server bit")
}
if h.byteOrder() != binary.BigEndian {
t.Error("byteOrder should be big-endian")
}
if h.Size != 0x00010203 {
t.Errorf("size = %#x, want 0x00010203", h.Size)
}
}
func TestHeaderPredicates(t *testing.T) {
le := PVAHeader{Flags: flagApp}
if !le.isLittleEndian() || le.isFromServer() || le.isControl() {
t.Errorf("app/LE header predicates wrong: %+v", le)
}
ctrl := PVAHeader{Flags: flagControl}
if !ctrl.isControl() {
t.Error("control header should report isControl")
}
}
// ---- BuildMessage -----------------------------------------------------
func TestBuildMessage(t *testing.T) {
payload := []byte{1, 2, 3, 4, 5}
// Pass the server flag too; BuildMessage must clear it (client direction).
msg := BuildMessage(CmdCreateChannel, flagFromServer, payload)
h, err := ReadHeader(bytes.NewReader(msg))
if err != nil {
t.Fatal(err)
}
if h.Command != CmdCreateChannel {
t.Errorf("command = %#x, want %#x", h.Command, CmdCreateChannel)
}
if h.isFromServer() {
t.Error("BuildMessage must clear the from-server flag")
}
if int(h.Size) != len(payload) {
t.Errorf("size = %d, want %d", h.Size, len(payload))
}
if got := msg[headerSize:]; !bytes.Equal(got, payload) {
t.Errorf("payload = %v, want %v", got, payload)
}
}
// ---- Status decoding --------------------------------------------------
func TestReadStatusOKShort(t *testing.T) {
s, err := ReadStatus(bytes.NewReader([]byte{StatusOK}), binary.LittleEndian)
if err != nil {
t.Fatal(err)
}
if !s.OK() || s.Error() != "" {
t.Errorf("short OK status: got %+v", s)
}
}
func TestReadStatusError(t *testing.T) {
var buf bytes.Buffer
buf.WriteByte(StatusError)
buf.WriteByte(0x04) // compact size 4
buf.WriteString("boom")
buf.WriteByte(0x00) // empty stack
s, err := ReadStatus(&buf, binary.LittleEndian)
if err != nil {
t.Fatal(err)
}
if s.OK() {
t.Error("error status should not be OK")
}
if s.Message != "boom" {
t.Errorf("message = %q, want boom", s.Message)
}
if s.Error() == "" {
t.Error("Error() should be non-empty for an error status")
}
}
func TestReadStatusTruncated(t *testing.T) {
if _, err := ReadStatus(bytes.NewReader(nil), binary.LittleEndian); err == nil {
t.Error("empty status: want error")
}
// type byte present but the message string is missing.
if _, err := ReadStatus(bytes.NewReader([]byte{StatusError}), binary.LittleEndian); err == nil {
t.Error("status missing message: want error")
}
}
// ---- readPVAString ----------------------------------------------------
func TestReadPVAString(t *testing.T) {
// Short form.
short := append([]byte{0x03}, []byte("abc")...)
s, err := readPVAString(bytes.NewReader(short), binary.LittleEndian)
if err != nil || s != "abc" {
t.Errorf("short string: got %q err %v", s, err)
}
// Empty.
s, err = readPVAString(bytes.NewReader([]byte{0x00}), binary.LittleEndian)
if err != nil || s != "" {
t.Errorf("empty string: got %q err %v", s, err)
}
// Extended form: 0xFF + int32 length + bytes.
var ext bytes.Buffer
ext.WriteByte(0xFF)
_ = binary.Write(&ext, binary.LittleEndian, int32(5))
ext.WriteString("hello")
s, err = readPVAString(&ext, binary.LittleEndian)
if err != nil || s != "hello" {
t.Errorf("extended string: got %q err %v", s, err)
}
}
// ---- env --------------------------------------------------------------
func TestAddrsFromEnv(t *testing.T) {
t.Setenv("EPICS_PVA_ADDR_LIST", "")
if got := addrsFromEnv(); got != nil {
t.Errorf("empty env: got %v, want nil", got)
}
t.Setenv("EPICS_PVA_ADDR_LIST", " 1.2.3.4 5.6.7.8 ")
got := addrsFromEnv()
if len(got) != 2 || got[0] != "1.2.3.4" || got[1] != "5.6.7.8" {
t.Errorf("addr list: got %v", got)
}
}