mirror of
https://github.com/open-gitagent/langship.sh.git
synced 2026-08-03 07:21:04 +02:00
130 lines
3.9 KiB
Go
130 lines
3.9 KiB
Go
package engine
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/lyzrai/flow/pkg/models"
|
|
)
|
|
|
|
// helper: build a context with a single upstream node Producer that has output 0.
|
|
func ctxWith(produced models.Item) *ExecutionContext {
|
|
wf := &models.WorkflowDefinition{Nodes: []models.NodeDef{{Name: "Producer"}, {Name: "Consumer"}}}
|
|
dag, _ := BuildDAG(&models.WorkflowDefinition{
|
|
Nodes: []models.NodeDef{
|
|
{ID: "1", Name: "Producer", Type: "flow-nodes-base.set"},
|
|
{ID: "2", Name: "Consumer", Type: "flow-nodes-base.noOp"},
|
|
},
|
|
Connections: []models.ConnectionDef{
|
|
{SourceNode: "Producer", TargetNode: "Consumer", SourceOutputIndex: 0, TargetInputIndex: 0},
|
|
},
|
|
})
|
|
c := NewExecutionContext(wf, dag)
|
|
c.SetOutput("Producer", 0, []models.Item{produced})
|
|
return c
|
|
}
|
|
|
|
func TestResolveString_dollarJsonField(t *testing.T) {
|
|
c := ctxWith(models.Item{"name": "ada", "n": float64(42)})
|
|
got := resolveString("={{ $json.name }}", c, "Consumer")
|
|
if got != "ada" {
|
|
t.Fatalf("got %v want ada", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveString_dollarJsonNumberPreservesType(t *testing.T) {
|
|
c := ctxWith(models.Item{"n": float64(42)})
|
|
got := resolveString("={{ $json.n }}", c, "Consumer")
|
|
if got != float64(42) {
|
|
t.Fatalf("got %T %v, want float64 42", got, got)
|
|
}
|
|
}
|
|
|
|
func TestResolveString_dollarParenNodeReference(t *testing.T) {
|
|
c := ctxWith(models.Item{"k": "v"})
|
|
got := resolveString(`={{ $('Producer').json.k }}`, c, "Consumer")
|
|
if got != "v" {
|
|
t.Fatalf("got %v want v", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveString_dollarNodeBracketReference(t *testing.T) {
|
|
c := ctxWith(models.Item{"k": "v"})
|
|
got := resolveString(`={{ $node["Producer"].json.k }}`, c, "Consumer")
|
|
if got != "v" {
|
|
t.Fatalf("got %v want v", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveString_interpolation(t *testing.T) {
|
|
c := ctxWith(models.Item{"name": "ada"})
|
|
got := resolveString("hi {{ $json.name }}", c, "Consumer")
|
|
if got != "hi ada" {
|
|
t.Fatalf("got %q want %q", got, "hi ada")
|
|
}
|
|
}
|
|
|
|
func TestResolveString_jsArithmetic(t *testing.T) {
|
|
c := ctxWith(models.Item{"n": float64(7)})
|
|
got := resolveString("={{ $json.n + 3 }}", c, "Consumer")
|
|
// goja returns int64 for integer arithmetic.
|
|
if got != int64(10) && got != float64(10) {
|
|
t.Fatalf("got %T %v want 10", got, got)
|
|
}
|
|
}
|
|
|
|
func TestResolveString_unknownField_returnsNil(t *testing.T) {
|
|
c := ctxWith(models.Item{"k": "v"})
|
|
got := resolveString("={{ $json.missing }}", c, "Consumer")
|
|
if got != nil {
|
|
t.Fatalf("got %v, want nil for missing field", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveExpressions_recursive(t *testing.T) {
|
|
c := ctxWith(models.Item{"name": "ada", "age": float64(7)})
|
|
in := map[string]any{
|
|
"top": "={{ $json.name }}",
|
|
"nested": map[string]any{
|
|
"k": "={{ $json.age }}",
|
|
},
|
|
"list": []any{"={{ $json.name }}", "static"},
|
|
}
|
|
got := ResolveExpressions(in, c, "Consumer")
|
|
wantNested := map[string]any{"k": float64(7)}
|
|
if !reflect.DeepEqual(got["nested"], wantNested) {
|
|
t.Errorf("nested: got %+v want %+v", got["nested"], wantNested)
|
|
}
|
|
wantList := []any{"ada", "static"}
|
|
if !reflect.DeepEqual(got["list"], wantList) {
|
|
t.Errorf("list: got %+v want %+v", got["list"], wantList)
|
|
}
|
|
if got["top"] != "ada" {
|
|
t.Errorf("top: got %v", got["top"])
|
|
}
|
|
}
|
|
|
|
func TestTraverseField_dotPath(t *testing.T) {
|
|
item := models.Item{
|
|
"user": map[string]any{"name": "ada", "addr": map[string]any{"city": "London"}},
|
|
}
|
|
if got := traverseField(item, "user.name"); got != "ada" {
|
|
t.Errorf("got %v", got)
|
|
}
|
|
if got := traverseField(item, "user.addr.city"); got != "London" {
|
|
t.Errorf("got %v", got)
|
|
}
|
|
if got := traverseField(item, "user.addr.zip"); got != nil {
|
|
t.Errorf("expected nil for missing path, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveString_jsEvalFailureReturnsExpressionLiteral(t *testing.T) {
|
|
c := ctxWith(models.Item{})
|
|
got := resolveString("={{ this is not js }}", c, "Consumer")
|
|
// Failure path returns "{{ expr }}" so the broken expression is visible at runtime.
|
|
if got != "{{ this is not js }}" {
|
|
t.Fatalf("got %v", got)
|
|
}
|
|
}
|