Done config
This commit is contained in:
@@ -41,6 +41,7 @@ func Apply(set ConfigSet, inst ConfigInstance, write WriteFunc) ApplyResult {
|
||||
res.Entries = append(res.Entries, e)
|
||||
continue
|
||||
}
|
||||
v = p.normalize(v)
|
||||
e.Value = v
|
||||
if err := write(p.DS, p.Signal, v); err != nil {
|
||||
e.Error = err.Error()
|
||||
|
||||
@@ -51,6 +51,37 @@ func TestApplyUsesDefaultWhenNoValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyArrayNormalizes(t *testing.T) {
|
||||
set := ConfigSet{ID: "s", Name: "s", Parameters: []Parameter{
|
||||
{Key: "wf", DS: "d", Signal: "WF", Type: TypeFloatArray},
|
||||
}}
|
||||
// JSON decoding yields []any of float64 — apply must hand the datasource a []float64.
|
||||
inst := ConfigInstance{ID: "i", SetID: "s", Values: map[string]any{"wf": []any{1.0, 2.0, 3.0}}}
|
||||
var got any
|
||||
res := Apply(set, inst, func(_, _ string, value any) error { got = value; return nil })
|
||||
if res.Applied != 1 {
|
||||
t.Fatalf("applied=%d", res.Applied)
|
||||
}
|
||||
arr, ok := got.([]float64)
|
||||
if !ok || len(arr) != 3 || arr[0] != 1 || arr[2] != 3 {
|
||||
t.Fatalf("want []float64{1,2,3}, got %T %v", got, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArrayValidation(t *testing.T) {
|
||||
lo := 0.0
|
||||
p := Parameter{Key: "wf", DS: "d", Signal: "S", Type: TypeFloatArray, Min: &lo}
|
||||
if err := p.checkValue([]any{1.0, 2.0}); err != nil {
|
||||
t.Fatalf("valid array rejected: %v", err)
|
||||
}
|
||||
if err := p.checkValue([]any{1.0, -5.0}); err == nil {
|
||||
t.Fatal("expected out-of-range element to be rejected")
|
||||
}
|
||||
if err := p.checkValue("notarray"); err == nil {
|
||||
t.Fatal("expected non-array value to be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyRecordsFailures(t *testing.T) {
|
||||
set := ConfigSet{
|
||||
ID: "set1", Name: "s",
|
||||
|
||||
@@ -16,16 +16,17 @@ import (
|
||||
type ParamType string
|
||||
|
||||
const (
|
||||
TypeFloat ParamType = "float64"
|
||||
TypeInt ParamType = "int64"
|
||||
TypeBool ParamType = "bool"
|
||||
TypeString ParamType = "string"
|
||||
TypeEnum ParamType = "enum"
|
||||
TypeFloat ParamType = "float64"
|
||||
TypeInt ParamType = "int64"
|
||||
TypeBool ParamType = "bool"
|
||||
TypeString ParamType = "string"
|
||||
TypeEnum ParamType = "enum"
|
||||
TypeFloatArray ParamType = "float64[]" // waveform; value is a list of numbers
|
||||
)
|
||||
|
||||
func (t ParamType) valid() bool {
|
||||
switch t {
|
||||
case TypeFloat, TypeInt, TypeBool, TypeString, TypeEnum:
|
||||
case TypeFloat, TypeInt, TypeBool, TypeString, TypeEnum, TypeFloatArray:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -197,10 +198,57 @@ func (p Parameter) checkValue(v any) error {
|
||||
if !slices.Contains(p.EnumValues, s) {
|
||||
return fmt.Errorf("value %q is not an allowed enum value", s)
|
||||
}
|
||||
case TypeFloatArray:
|
||||
arr, err := toFloatArray(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, f := range arr {
|
||||
if p.Min != nil && f < *p.Min {
|
||||
return fmt.Errorf("element %d value %v below minimum %v", i, f, *p.Min)
|
||||
}
|
||||
if p.Max != nil && f > *p.Max {
|
||||
return fmt.Errorf("element %d value %v above maximum %v", i, f, *p.Max)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalize coerces a JSON-decoded value into the canonical Go type the
|
||||
// datasource write path expects. Array parameters become []float64 (JSON yields
|
||||
// []any); scalar values are returned unchanged.
|
||||
func (p Parameter) normalize(v any) any {
|
||||
if p.Type == TypeFloatArray {
|
||||
if arr, err := toFloatArray(v); err == nil {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// toFloatArray coerces a JSON-decoded array value to []float64. JSON
|
||||
// unmarshalling yields []any of float64, but a native []float64 is also
|
||||
// accepted.
|
||||
func toFloatArray(v any) ([]float64, error) {
|
||||
switch a := v.(type) {
|
||||
case []float64:
|
||||
return a, nil
|
||||
case []any:
|
||||
out := make([]float64, len(a))
|
||||
for i, e := range a {
|
||||
f, err := toFloat(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("element %d: %w", i, err)
|
||||
}
|
||||
out[i] = f
|
||||
}
|
||||
return out, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("value %v is not an array", v)
|
||||
}
|
||||
}
|
||||
|
||||
// toFloat coerces a JSON-decoded numeric value to float64. JSON unmarshalling
|
||||
// yields float64 for numbers, but values may also arrive as int or string.
|
||||
func toFloat(v any) (float64, error) {
|
||||
|
||||
Reference in New Issue
Block a user