Files
MARTe-Integrated-Components/Common/Client/go/wshub/calibration_test.go
T

184 lines
5.9 KiB
Go

package wshub
import (
"math"
"testing"
)
func TestCalConfigNormalise(t *testing.T) {
cases := []struct {
name string
in CalConfig
want bool
wantUnit string
}{
{"plain", CalConfig{Source: "wave", Signal: "Adc", Scale: 2, Offset: -1, Unit: "V"}, true, "V"},
{"trims", CalConfig{Source: " wave ", Signal: " Adc ", Scale: 1, Unit: " V "}, true, "V"},
{"emptySource", CalConfig{Signal: "Adc", Scale: 1}, false, ""},
{"emptySignal", CalConfig{Source: "wave", Scale: 1}, false, ""},
{"zeroScale", CalConfig{Source: "wave", Signal: "Adc", Scale: 0}, false, ""},
{"nanScale", CalConfig{Source: "wave", Signal: "Adc", Scale: math.NaN()}, false, ""},
{"infScale", CalConfig{Source: "wave", Signal: "Adc", Scale: math.Inf(1)}, false, ""},
{"nanOffset", CalConfig{Source: "wave", Signal: "Adc", Scale: 1, Offset: math.NaN()}, false, ""},
{"infOffset", CalConfig{Source: "wave", Signal: "Adc", Scale: 1, Offset: math.Inf(-1)}, false, ""},
{"negScaleOK", CalConfig{Source: "wave", Signal: "Adc", Scale: -1}, true, ""},
{"longUnit", CalConfig{Source: "wave", Signal: "Adc", Scale: 1,
Unit: "0123456789abcdefGHIJ"}, true, "0123456789abcdef"},
}
for _, c := range cases {
got := c.in
if ok := got.Normalise(); ok != c.want {
t.Errorf("%s: Normalise() = %v, want %v", c.name, ok, c.want)
continue
}
if c.want && got.Unit != c.wantUnit {
t.Errorf("%s: Unit = %q, want %q", c.name, got.Unit, c.wantUnit)
}
}
if len("0123456789abcdef") != maxUnitLen {
t.Fatalf("test assumes maxUnitLen == 16, got %d", maxUnitLen)
}
}
func TestCalTableSetListAndIdentityRemoval(t *testing.T) {
tab := newCalTable()
if !tab.Set(CalConfig{Source: "b", Signal: "Y", Scale: 3, Offset: 1, Unit: "A"}) {
t.Fatal("Set(b/Y) rejected")
}
if !tab.Set(CalConfig{Source: "a", Signal: "X", Scale: 2}) {
t.Fatal("Set(a/X) rejected")
}
if tab.Set(CalConfig{Source: "a", Signal: "Z", Scale: 0}) {
t.Error("Set with scale=0 accepted, want rejected")
}
got := tab.List()
if len(got) != 2 {
t.Fatalf("List() = %d entries, want 2", len(got))
}
// Sorted by source then signal.
if got[0].Source != "a" || got[1].Source != "b" {
t.Errorf("List() order = %q,%q, want a,b", got[0].Source, got[1].Source)
}
// An identity entry removes the stored one.
if !tab.Set(CalConfig{Source: "a", Signal: "X", Scale: 1, Offset: 0, Unit: ""}) {
t.Fatal("identity Set rejected")
}
if got := tab.List(); len(got) != 1 || got[0].Source != "b" {
t.Errorf("after identity Set, List() = %+v, want only b/Y", got)
}
}
func TestCalTableReplace(t *testing.T) {
tab := newCalTable()
tab.Set(CalConfig{Source: "old", Signal: "X", Scale: 5})
tab.Replace([]CalConfig{
{Source: "new", Signal: "Y", Scale: 2},
{Source: "bad", Signal: "Z", Scale: 0}, // invalid → dropped
{Source: "id", Signal: "W", Scale: 1, Offset: 0, Unit: ""}, // identity → dropped
})
got := tab.List()
if len(got) != 1 || got[0].Source != "new" {
t.Fatalf("List() = %+v, want only new/Y", got)
}
}
func TestParseConfigFileCurrentFormat(t *testing.T) {
// A file written by the current binaries — sources only, spaces after colons.
data := []byte(`[
{
"label": "wave",
"addr": "127.0.0.1:44500"
},
{
"label": "mc",
"addr": "127.0.0.1:44501",
"multicastGroup": "239.0.0.1",
"dataPort": 44502
}
]`)
srcs, cals, err := parseConfigFile(data)
if err != nil {
t.Fatalf("parseConfigFile: %v", err)
}
if len(srcs) != 2 || len(cals) != 0 {
t.Fatalf("got %d sources / %d cals, want 2 / 0", len(srcs), len(cals))
}
if srcs[1].MulticastGroup != "239.0.0.1" || srcs[1].DataPort != 44502 {
t.Errorf("multicast source = %+v", srcs[1])
}
}
func TestParseConfigFileMixed(t *testing.T) {
data := []byte(`[
{"label":"wave","addr":"127.0.0.1:44500"},
{"source":"wave","signal":"Adc","scale":0.00030518,"offset":-1.25,"unit":"V"},
{"source":"wave","signal":"Bare"},
{"source":"wave","signal":"Bad","scale":0},
{"nonsense":true}
]`)
srcs, cals, err := parseConfigFile(data)
if err != nil {
t.Fatalf("parseConfigFile: %v", err)
}
if len(srcs) != 1 {
t.Fatalf("got %d sources, want 1", len(srcs))
}
if len(cals) != 2 {
t.Fatalf("got %d cals, want 2 (Adc and Bare; Bad is invalid)", len(cals))
}
if cals[0].Scale != 0.00030518 || cals[0].Offset != -1.25 || cals[0].Unit != "V" {
t.Errorf("Adc = %+v", cals[0])
}
// Absent scale/offset default to the identity values, not to zero.
if cals[1].Signal != "Bare" || cals[1].Scale != 1 || cals[1].Offset != 0 {
t.Errorf("Bare = %+v, want scale 1 / offset 0", cals[1])
}
}
func TestParseConfigFileMalformed(t *testing.T) {
if _, _, err := parseConfigFile([]byte("not json")); err == nil {
t.Error("parseConfigFile(garbage) = nil error, want error")
}
}
func TestEncodeConfigFileRoundTrip(t *testing.T) {
srcs := []SourceConfig{
{Label: "wave", Addr: "127.0.0.1:44500"},
{Label: "mc", Addr: "127.0.0.1:44501", MulticastGroup: "239.0.0.1", DataPort: 44502},
}
cals := []CalConfig{
{Source: "wave", Signal: "Adc", Scale: 0.5, Offset: 0, Unit: "V"},
}
data, err := encodeConfigFile(srcs, cals)
if err != nil {
t.Fatalf("encodeConfigFile: %v", err)
}
gotSrcs, gotCals, err := parseConfigFile(data)
if err != nil {
t.Fatalf("parseConfigFile(encoded): %v\n%s", err, data)
}
if len(gotSrcs) != 2 || len(gotCals) != 1 {
t.Fatalf("round-trip gave %d sources / %d cals, want 2 / 1\n%s",
len(gotSrcs), len(gotCals), data)
}
if gotSrcs[1] != srcs[1] {
t.Errorf("source round-trip: got %+v, want %+v", gotSrcs[1], srcs[1])
}
if gotCals[0] != cals[0] {
t.Errorf("cal round-trip: got %+v, want %+v", gotCals[0], cals[0])
}
// offset 0 must survive as an explicit field, not be dropped by omitempty.
if !bytesContains(data, []byte(`"offset": 0`)) {
t.Errorf("encoded file lost the zero offset:\n%s", data)
}
}
func bytesContains(hay, needle []byte) bool {
for i := 0; i+len(needle) <= len(hay); i++ {
if string(hay[i:i+len(needle)]) == string(needle) {
return true
}
}
return false
}