110 lines
3.1 KiB
Go
110 lines
3.1 KiB
Go
package ca
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/uopi/goca/proto"
|
|
)
|
|
|
|
// ---- encodePut: every DBF branch + error paths -----------------------
|
|
|
|
func TestEncodePut(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
dbf int
|
|
v any
|
|
wantDBR uint16
|
|
}{
|
|
{"double", proto.DBFDouble, 1.5, proto.DBRDouble},
|
|
{"float", proto.DBFFloat, float32(2.0), proto.DBRDouble},
|
|
{"long", proto.DBFLong, int(3), proto.DBRLong},
|
|
{"short", proto.DBFShort, int16(4), proto.DBRShort},
|
|
{"char", proto.DBFChar, int(5), proto.DBRShort},
|
|
{"enum", proto.DBFEnum, int(1), proto.DBRShort},
|
|
{"string", proto.DBFString, "hi", proto.DBRString},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
dbr, payload, err := encodePut(c.dbf, c.v)
|
|
if err != nil {
|
|
t.Fatalf("encodePut: %v", err)
|
|
}
|
|
if dbr != c.wantDBR {
|
|
t.Errorf("dbr = %d, want %d", dbr, c.wantDBR)
|
|
}
|
|
if len(payload) == 0 {
|
|
t.Error("empty payload")
|
|
}
|
|
})
|
|
}
|
|
|
|
// Coercion failures propagate.
|
|
if _, _, err := encodePut(proto.DBFDouble, "nope"); err == nil {
|
|
t.Error("double from string: want error")
|
|
}
|
|
if _, _, err := encodePut(proto.DBFLong, "nope"); err == nil {
|
|
t.Error("long from string: want error")
|
|
}
|
|
if _, _, err := encodePut(proto.DBFShort, "nope"); err == nil {
|
|
t.Error("short from string: want error")
|
|
}
|
|
// Unsupported field type.
|
|
if _, _, err := encodePut(9999, 1); err == nil {
|
|
t.Error("unsupported DBF: want error")
|
|
}
|
|
}
|
|
|
|
// ---- NewClient: error path + default name/host -----------------------
|
|
|
|
func TestNewClientNoAddrs(t *testing.T) {
|
|
if _, err := NewClient(context.Background(), Config{AutoAddrList: false}); err == nil {
|
|
t.Error("NewClient with no addresses: want error")
|
|
}
|
|
}
|
|
|
|
func TestNewClientDefaultsNameHost(t *testing.T) {
|
|
// AddrList present but ClientName/HostName empty → default branches run.
|
|
cli, err := NewClient(context.Background(), Config{
|
|
AddrList: []string{"127.0.0.1:5064"},
|
|
AutoAddrList: false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewClient: %v", err)
|
|
}
|
|
defer cli.Close()
|
|
if cli.cfg.ClientName == "" {
|
|
t.Error("ClientName should be defaulted")
|
|
}
|
|
}
|
|
|
|
// ---- EncodeSearchReply with an explicit server IP --------------------
|
|
|
|
func TestEncodeSearchReplyExplicitIP(t *testing.T) {
|
|
pkt := EncodeSearchReply(7, net.ParseIP("10.1.2.3"), 5064)
|
|
h, _, err := proto.DecodeHeader(newBytesReader(pkt))
|
|
if err != nil {
|
|
t.Fatalf("DecodeHeader: %v", err)
|
|
}
|
|
if h.Command != proto.CmdSearch {
|
|
t.Errorf("command = %d, want CmdSearch", h.Command)
|
|
}
|
|
}
|
|
|
|
// ---- parseReply robustness -------------------------------------------
|
|
|
|
func TestParseReplyTruncated(t *testing.T) {
|
|
se := &searchEngine{waiters: make(map[uint32]*searchWaiter)}
|
|
src := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5064}
|
|
// Must not panic on a too-short datagram.
|
|
se.parseReply([]byte{0x00, 0x01}, src)
|
|
}
|
|
|
|
func TestParseReplyUnknownSearchID(t *testing.T) {
|
|
se := &searchEngine{waiters: make(map[uint32]*searchWaiter)}
|
|
src := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5064}
|
|
// Valid reply but no waiter is registered for this search ID → dropped.
|
|
se.parseReply(EncodeSearchReply(12345, nil, 5064), src)
|
|
}
|