diff --git a/internal/controllogic/engine_helpers_test.go b/internal/controllogic/engine_helpers_test.go index 1ef5d05..59a51ad 100644 --- a/internal/controllogic/engine_helpers_test.go +++ b/internal/controllogic/engine_helpers_test.go @@ -87,7 +87,7 @@ func TestCoerceParamValue(t *testing.T) { } func TestSign(t *testing.T) { - if sign(5) != 1 || sign(-5) != -1 || sign(0) != 0 { - t.Errorf("sign mismatch: %d %d %d", sign(5), sign(-5), sign(0)) + if signOf(5) != 1 || signOf(-5) != -1 || signOf(0) != 0 { + t.Errorf("sign mismatch: %d %d %d", signOf(5), signOf(-5), signOf(0)) } } diff --git a/internal/controllogic/engine_test.go b/internal/controllogic/engine_test.go index e43a148..e092784 100644 --- a/internal/controllogic/engine_test.go +++ b/internal/controllogic/engine_test.go @@ -60,6 +60,54 @@ func TestArrayClearNode(t *testing.T) { } } +func TestArraySetNode(t *testing.T) { + g := Graph{ + ID: "g", Name: "n", + StateVars: []StateVar{{Name: "buf", Type: "array", Initial: "[0,0,0]", Sizing: "dynamic"}}, + Nodes: []Node{ + {ID: "t", Kind: "trigger.timer", Params: map[string]string{"interval": "1000"}}, + {ID: "s", Kind: "action.array.set", Params: map[string]string{"array": "buf", "index": "1", "expr": "9"}}, + }, + Wires: []Wire{{From: "t", To: "s"}}, + } + cg := runFlowOnce(t, g, "t") + if got := cg.getLocal("buf"); !reflect.DeepEqual(got, []Value{0.0, 9.0, 0.0}) { + t.Fatalf("after set buf = %#v", got) + } +} + +func TestArrayRemoveNode(t *testing.T) { + g := Graph{ + ID: "g", Name: "n", + StateVars: []StateVar{{Name: "buf", Type: "array", Initial: "[10,20,30]", Sizing: "dynamic"}}, + Nodes: []Node{ + {ID: "t", Kind: "trigger.timer", Params: map[string]string{"interval": "1000"}}, + {ID: "r", Kind: "action.array.remove", Params: map[string]string{"array": "buf", "index": "-1"}}, + }, + Wires: []Wire{{From: "t", To: "r"}}, + } + cg := runFlowOnce(t, g, "t") + if got := cg.getLocal("buf"); !reflect.DeepEqual(got, []Value{10.0, 20.0}) { + t.Fatalf("after remove buf = %#v", got) + } +} + +func TestArrayPopNode(t *testing.T) { + g := Graph{ + ID: "g", Name: "n", + StateVars: []StateVar{{Name: "buf", Type: "array", Initial: "[1,2,3]", Sizing: "dynamic"}}, + Nodes: []Node{ + {ID: "t", Kind: "trigger.timer", Params: map[string]string{"interval": "1000"}}, + {ID: "p", Kind: "action.array.pop", Params: map[string]string{"array": "buf"}}, + }, + Wires: []Wire{{From: "t", To: "p"}}, + } + cg := runFlowOnce(t, g, "t") + if got := cg.getLocal("buf"); !reflect.DeepEqual(got, []Value{1.0, 2.0}) { + t.Fatalf("after pop buf = %#v", got) + } +} + func TestCompileInitsLocalsFromDecls(t *testing.T) { g := Graph{ ID: "g", Name: "n", diff --git a/internal/controllogic/expr.go b/internal/controllogic/expr.go index 367f53f..35aec4c 100644 --- a/internal/controllogic/expr.go +++ b/internal/controllogic/expr.go @@ -353,8 +353,6 @@ func signOf(x float64) int { } } -// sign is an alias for signOf, kept for backward compatibility with existing tests. -func sign(x float64) int { return signOf(x) } func clampIdx(i, length int) int { if i < 0 { i = length + i