135 lines
4.9 KiB
Go
135 lines
4.9 KiB
Go
package confmgr
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestParamTypeValid covers the valid/invalid branches of ParamType.valid.
|
|
func TestParamTypeValid(t *testing.T) {
|
|
for _, ok := range []ParamType{TypeFloat, TypeInt, TypeBool, TypeString, TypeEnum, TypeFloatArray} {
|
|
if !ok.valid() {
|
|
t.Errorf("%q should be valid", ok)
|
|
}
|
|
}
|
|
if ParamType("bogus").valid() {
|
|
t.Error("bogus type should be invalid")
|
|
}
|
|
}
|
|
|
|
// TestCheckValue exercises every type branch of Parameter.checkValue, including
|
|
// the type-mismatch and range-violation error paths.
|
|
func TestCheckValue(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
p Parameter
|
|
v any
|
|
wantErr bool
|
|
}{
|
|
{"float ok", Parameter{Type: TypeFloat}, 1.5, false},
|
|
{"float from string", Parameter{Type: TypeFloat}, "2.5", false},
|
|
{"float not numeric", Parameter{Type: TypeFloat}, true, true},
|
|
{"float below min", Parameter{Type: TypeFloat, Min: fptr(0)}, -1.0, true},
|
|
{"float above max", Parameter{Type: TypeFloat, Max: fptr(10)}, 11.0, true},
|
|
{"int ok", Parameter{Type: TypeInt}, 4.0, false},
|
|
{"int non-integer", Parameter{Type: TypeInt}, 4.5, true},
|
|
{"bool ok", Parameter{Type: TypeBool}, true, false},
|
|
{"bool wrong type", Parameter{Type: TypeBool}, 1.0, true},
|
|
{"string ok", Parameter{Type: TypeString}, "hi", false},
|
|
{"string wrong type", Parameter{Type: TypeString}, 1.0, true},
|
|
{"enum ok", Parameter{Type: TypeEnum, EnumValues: []string{"a", "b"}}, "b", false},
|
|
{"enum not string", Parameter{Type: TypeEnum, EnumValues: []string{"a"}}, 1.0, true},
|
|
{"enum not allowed", Parameter{Type: TypeEnum, EnumValues: []string{"a"}}, "z", true},
|
|
{"array ok", Parameter{Type: TypeFloatArray}, []any{1.0, 2.0}, false},
|
|
{"array native", Parameter{Type: TypeFloatArray}, []float64{1, 2}, false},
|
|
{"array not array", Parameter{Type: TypeFloatArray}, 1.0, true},
|
|
{"array elem below min", Parameter{Type: TypeFloatArray, Min: fptr(0)}, []any{-1.0}, true},
|
|
{"array elem above max", Parameter{Type: TypeFloatArray, Max: fptr(5)}, []any{9.0}, true},
|
|
{"array bad elem", Parameter{Type: TypeFloatArray}, []any{"nope"}, true},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err := tc.p.checkValue(tc.v)
|
|
if tc.wantErr && err == nil {
|
|
t.Errorf("checkValue(%v): want error", tc.v)
|
|
}
|
|
if !tc.wantErr && err != nil {
|
|
t.Errorf("checkValue(%v): unexpected error %v", tc.v, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestValidateInvalidType covers the invalid-type branch of ConfigSet.Validate.
|
|
func TestValidateInvalidType(t *testing.T) {
|
|
set := ConfigSet{Name: "x", Parameters: []Parameter{
|
|
{Key: "a", DS: "d", Signal: "s", Type: ParamType("weird")},
|
|
}}
|
|
if err := set.Validate(); err == nil {
|
|
t.Error("invalid parameter type: want error")
|
|
}
|
|
}
|
|
|
|
// TestValidateEnumRequiresValues covers the enum-without-values branch.
|
|
func TestValidateEnumRequiresValues(t *testing.T) {
|
|
set := ConfigSet{Name: "x", Parameters: []Parameter{
|
|
{Key: "a", DS: "d", Signal: "s", Type: TypeEnum},
|
|
}}
|
|
if err := set.Validate(); err == nil {
|
|
t.Error("enum without values: want error")
|
|
}
|
|
}
|
|
|
|
// TestValidateMinGreaterThanMax covers the min>max branch.
|
|
func TestValidateMinGreaterThanMax(t *testing.T) {
|
|
set := ConfigSet{Name: "x", Parameters: []Parameter{
|
|
{Key: "a", DS: "d", Signal: "s", Type: TypeFloat, Min: fptr(10), Max: fptr(1)},
|
|
}}
|
|
if err := set.Validate(); err == nil {
|
|
t.Error("min>max: want error")
|
|
}
|
|
}
|
|
|
|
// TestValidateAgainstMandatoryNoDefault covers the mandatory-without-default
|
|
// branch of ValidateAgainst.
|
|
func TestValidateAgainstMandatoryNoDefault(t *testing.T) {
|
|
set := ConfigSet{Name: "x", Parameters: []Parameter{
|
|
{Key: "req", DS: "d", Signal: "s", Type: TypeFloat, Mandatory: true},
|
|
}}
|
|
inst := ConfigInstance{SetID: "x", Values: map[string]any{}}
|
|
if err := inst.ValidateAgainst(set); err == nil {
|
|
t.Error("missing mandatory value: want error")
|
|
}
|
|
// Providing the value clears the error.
|
|
inst.Values["req"] = 1.0
|
|
if err := inst.ValidateAgainst(set); err != nil {
|
|
t.Errorf("with value: unexpected error %v", err)
|
|
}
|
|
}
|
|
|
|
// TestResolveAndNormalize covers Resolve fallbacks and array normalization.
|
|
func TestResolveAndNormalize(t *testing.T) {
|
|
p := Parameter{Key: "v", Type: TypeFloat, Default: 7.0}
|
|
inst := ConfigInstance{Values: map[string]any{}}
|
|
if got, ok := inst.Resolve(p); !ok || got != 7.0 {
|
|
t.Errorf("Resolve default: got %v,%v want 7,true", got, ok)
|
|
}
|
|
inst.Values["v"] = 3.0
|
|
if got, ok := inst.Resolve(p); !ok || got != 3.0 {
|
|
t.Errorf("Resolve value: got %v,%v want 3,true", got, ok)
|
|
}
|
|
// Optional param without default → no value.
|
|
if _, ok := inst.Resolve(Parameter{Key: "none", Type: TypeFloat}); ok {
|
|
t.Error("Resolve no-default: want ok=false")
|
|
}
|
|
|
|
arr := Parameter{Type: TypeFloatArray}
|
|
out := arr.normalize([]any{1.0, 2.0, 3.0})
|
|
if got, ok := out.([]float64); !ok || len(got) != 3 {
|
|
t.Errorf("normalize array: got %T %v", out, out)
|
|
}
|
|
// Non-array passthrough.
|
|
if got := arr.normalize("scalar"); got != "scalar" {
|
|
t.Errorf("normalize passthrough: got %v", got)
|
|
}
|
|
}
|