package api import ( "strings" "testing" ) func TestValidateModbusAddressAcceptsLANAddresses(t *testing.T) { for _, tc := range []struct { host string port int }{ {"10.2.1.55", 502}, {"192.168.1.40", 0}, // 0 means the standard port {"charger.local", 502}, {"fd00::1", 502}, } { if err := validateModbusAddress(tc.host, tc.port); err != nil { t.Errorf("validateModbusAddress(%q, %d) = %v, want nil", tc.host, tc.port, err) } } } // The server dials this address on the caller's behalf, so an address that // resolves back to the server would point it at its own services. func TestValidateModbusAddressRefusesLoopback(t *testing.T) { for _, host := range []string{"127.0.0.1", "::1", "localhost", "LocalHost", "0.0.0.0"} { err := validateModbusAddress(host, 502) if err == nil { t.Errorf("validateModbusAddress(%q) was accepted", host) continue } if !strings.Contains(err.Error(), "server itself") { t.Errorf("validateModbusAddress(%q) = %v, want it to say why", host, err) } } } func TestValidateModbusAddressRejectsMalformed(t *testing.T) { cases := []struct { name string host string port int }{ {"empty host", "", 502}, {"a URL rather than a host", "http://10.2.1.55/", 502}, {"host with a path", "10.2.1.55/modbus", 502}, {"port above the range", "10.2.1.55", 70000}, {"negative port", "10.2.1.55", -1}, } for _, tc := range cases { if err := validateModbusAddress(tc.host, tc.port); err == nil { t.Errorf("%s was accepted", tc.name) } } } func TestAnkerModbusConfigTrimsAndDefaults(t *testing.T) { cfg := ankerModbusConfig(ankerChargerBinding{ModbusHost: " 10.2.1.55 "}) if cfg.Host != "10.2.1.55" { t.Errorf("Host = %q, want it trimmed", cfg.Host) } if got := cfg.Address(); got != "10.2.1.55:502" { t.Errorf("Address = %q, want the standard port filled in", got) } cfg = ankerModbusConfig(ankerChargerBinding{ModbusHost: "10.2.1.55", ModbusPort: 1502}) if got := cfg.Address(); got != "10.2.1.55:1502" { t.Errorf("Address = %q, want 10.2.1.55:1502", got) } }