package proto_test import ( "bytes" "encoding/binary" "math" "testing" "github.com/uopi/goca/proto" ) // -------------------------------------------------------------------------- // // DBR_TIME_* variants not covered by proto_test.go // // -------------------------------------------------------------------------- // func TestDecodeTimeFloat(t *testing.T) { hdr := buildTimeHeader(0, 0, 0, 0) val := make([]byte, 4) binary.BigEndian.PutUint32(val, math.Float32bits(2.5)) tv, ok := proto.DecodeTimeValue(proto.DBRTimeFloat, 1, append(hdr, val...)) if !ok || math.Abs(float64(tv.Float)-2.5) > 1e-6 { t.Errorf("float: ok=%v Float=%g", ok, tv.Float) } } func TestDecodeTimeShort(t *testing.T) { hdr := buildTimeHeader(0, 0, 0, 0) val := []byte{0x00, 0x00, 0xFF, 0xD6} // 2-byte pad + int16(-42) tv, ok := proto.DecodeTimeValue(proto.DBRTimeShort, 1, append(hdr, val...)) if !ok || tv.Short != -42 { t.Errorf("short: ok=%v Short=%d", ok, tv.Short) } } func TestDecodeTimeChar(t *testing.T) { hdr := buildTimeHeader(0, 0, 0, 0) val := []byte{0x00, 0x00, 0x00, 0x41} // pad0 + pad1 + value 'A' tv, ok := proto.DecodeTimeValue(proto.DBRTimeChar, 1, append(hdr, val...)) if !ok || tv.Char != 0x41 { t.Errorf("char: ok=%v Char=%d", ok, tv.Char) } } func TestDecodeTimeUnknownType(t *testing.T) { hdr := buildTimeHeader(0, 0, 0, 0) if _, ok := proto.DecodeTimeValue(9999, 1, append(hdr, make([]byte, 16)...)); ok { t.Error("unknown DBR type should return false") } } // -------------------------------------------------------------------------- // // DBR_CTRL_LONG / DBR_CTRL_STRING // // -------------------------------------------------------------------------- // func TestDecodeCtrlLong(t *testing.T) { p := make([]byte, 48) binary.BigEndian.PutUint16(p[2:], 2) // severity = Major copy(p[4:], "counts") i32 := func(off int, v int32) { binary.BigEndian.PutUint32(p[off:], uint32(v)) } i32(12, 1000) // upper_disp i32(16, -10) // lower_disp i32(44, 777) // value cl, ok := proto.DecodeCtrlLong(p) if !ok { t.Fatal("DecodeCtrlLong returned false") } if cl.Units != "counts" || cl.Value != 777 || cl.UpperDispLimit != 1000 || cl.LowerDispLimit != -10 { t.Errorf("got %+v", cl) } if cl.Severity != proto.SeverityMajor { t.Errorf("severity = %v, want Major", cl.Severity) } if _, ok := proto.DecodeCtrlLong(make([]byte, 10)); ok { t.Error("short CtrlLong payload should return false") } } func TestDecodeCtrlString(t *testing.T) { p := make([]byte, 44) binary.BigEndian.PutUint16(p[2:], 1) // severity = Minor copy(p[4:], "READY") cs, ok := proto.DecodeCtrlString(p) if !ok { t.Fatal("DecodeCtrlString returned false") } if cs.Value != "READY" || cs.Severity != proto.SeverityMinor { t.Errorf("got %+v", cs) } if _, ok := proto.DecodeCtrlString(make([]byte, 10)); ok { t.Error("short CtrlString payload should return false") } } // -------------------------------------------------------------------------- // // EncodeShort // // -------------------------------------------------------------------------- // func TestEncodeShort(t *testing.T) { b := proto.EncodeShort(-7) if len(b) != 8 { t.Fatalf("len = %d, want 8", len(b)) } if got := int16(binary.BigEndian.Uint16(b)); got != -7 { t.Errorf("decoded = %d, want -7", got) } } // -------------------------------------------------------------------------- // // NativeCtrlType // // -------------------------------------------------------------------------- // func TestNativeCtrlType(t *testing.T) { cases := []struct { dbf int want uint16 }{ {proto.DBFDouble, proto.DBRCtrlDouble}, {proto.DBFFloat, proto.DBRCtrlDouble}, {proto.DBFLong, proto.DBRCtrlLong}, {proto.DBFShort, proto.DBRCtrlLong}, {proto.DBFChar, proto.DBRCtrlLong}, {proto.DBFEnum, proto.DBRCtrlEnum}, {proto.DBFString, proto.DBRCtrlString}, {9999, proto.DBRCtrlDouble}, // default } for _, c := range cases { if got := proto.NativeCtrlType(c.dbf); got != c.want { t.Errorf("NativeCtrlType(%d) = %d, want %d", c.dbf, got, c.want) } } } // -------------------------------------------------------------------------- // // DecodeHeader: extended encoding + error path // // -------------------------------------------------------------------------- // func TestDecodeHeaderExtended(t *testing.T) { raw := make([]byte, 24) binary.BigEndian.PutUint16(raw[0:], proto.CmdReadNotify) binary.BigEndian.PutUint16(raw[2:], 0xFFFF) // extended marker binary.BigEndian.PutUint16(raw[6:], 0x0000) binary.BigEndian.PutUint32(raw[16:], 70000) // real payload size binary.BigEndian.PutUint32(raw[20:], 5) // real count h, n, err := proto.DecodeHeader(bytes.NewReader(raw)) if err != nil { t.Fatal(err) } if n != 24 { t.Errorf("bytes read = %d, want 24", n) } if h.PayloadSize != 70000 || h.DataCount != 5 { t.Errorf("extended header = %+v", h) } } func TestDecodeHeaderTruncated(t *testing.T) { if _, _, err := proto.DecodeHeader(bytes.NewReader([]byte{0x00, 0x01})); err == nil { t.Error("truncated header: want error") } }