Files
kandev/apps/backend/internal/automation/interpolator_test.go
T

129 lines
4.2 KiB
Go

package automation
import (
"encoding/json"
"strings"
"testing"
)
func TestInterpolatePrompt_Scheduled(t *testing.T) {
data, _ := json.Marshal(map[string]string{"source": "scheduled", "timestamp": "2026-03-08T12:00:00Z"})
result := InterpolatePrompt("Run at {{trigger.timestamp}} by {{trigger.type}}", TriggerTypeScheduled, data)
if !strings.Contains(result, "scheduled") {
t.Errorf("expected trigger type in result, got %q", result)
}
// timestamp is generated at call time, just verify it's replaced
if strings.Contains(result, "{{trigger.timestamp}}") {
t.Error("expected {{trigger.timestamp}} to be replaced")
}
}
func TestInterpolatePrompt_PR(t *testing.T) {
data, _ := json.Marshal(map[string]any{
"number": 42,
"title": "Fix the bug",
"html_url": "https://github.com/org/repo/pull/42",
"author_login": "alice",
automationRepoKey: "org/repo",
"head_branch": "fix-bug",
automationBaseBranchKey: defaultBranchMain,
})
prompt := "Review PR #{{pr.number}} '{{pr.title}}' by {{pr.author}} in {{pr.repo}}"
result := InterpolatePrompt(prompt, TriggerTypeGitHubPR, data)
if !strings.Contains(result, "#42") {
t.Errorf("expected PR number, got %q", result)
}
if !strings.Contains(result, "Fix the bug") {
t.Errorf("expected PR title, got %q", result)
}
if !strings.Contains(result, "alice") {
t.Errorf("expected author, got %q", result)
}
}
func TestInterpolatePrompt_Webhook(t *testing.T) {
data, _ := json.Marshal(map[string]any{
"action": "deploy",
"env": "production",
})
prompt := "Webhook received: {{webhook.body}}, action={{data.action}}"
result := InterpolatePrompt(prompt, TriggerTypeWebhook, data)
if strings.Contains(result, "{{webhook.body}}") {
t.Error("expected {{webhook.body}} to be replaced")
}
if !strings.Contains(result, "deploy") {
t.Errorf("expected 'deploy' in result, got %q", result)
}
}
func TestInterpolatePrompt_Empty(t *testing.T) {
result := InterpolatePrompt("", TriggerTypeScheduled, json.RawMessage(`{}`))
if result != "" {
t.Errorf("expected empty, got %q", result)
}
}
func TestInterpolatePrompt_NoPlaceholders(t *testing.T) {
result := InterpolatePrompt("plain text", TriggerTypeScheduled, json.RawMessage(`{}`))
if result != "plain text" {
t.Errorf("expected 'plain text', got %q", result)
}
}
func TestInterpolatePrompt_WebhookNestedPath(t *testing.T) {
// Real-world webhook payloads carry nested fields like
// pull_request.number, commits[0].message, alert.severity. Authors
// should be able to template those directly into the prompt.
body := []byte(`{
"action": "opened",
"pull_request": {
"number": 17,
"title": "Add webhook support",
"user": {"login": "carol"}
},
"commits": [
{"message": "first"},
{"message": "second"}
],
"x-request-id": "abc-123"
}`)
cases := []struct {
name string
template string
want string
}{
{"nested object", "PR #{{webhook.pull_request.number}}", "PR #17"},
{"deeply nested", "by {{webhook.pull_request.user.login}}", "by carol"},
{"array index", "first commit: {{webhook.commits.0.message}}", "first commit: first"},
{"second array index", "second: {{webhook.commits.1.message}}", "second: second"},
{"data alias", "action={{data.action}}", "action=opened"},
{"data nested", "title={{data.pull_request.title}}", "title=Add webhook support"},
{"missing path drops", "x={{webhook.missing.field}}", "x="},
{"out-of-range index drops", "x={{webhook.commits.99.message}}", "x="},
{"kebab-case key", "id={{webhook.x-request-id}}", "id=abc-123"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := InterpolatePrompt(tc.template, TriggerTypeWebhook, body)
if got != tc.want {
t.Errorf("got %q, want %q", got, tc.want)
}
})
}
}
func TestInterpolatePrompt_PathPlaceholderCoercion(t *testing.T) {
// Non-string leaf values are coerced through toString. Booleans and
// integers should round-trip in the obvious way.
body := []byte(`{"count": 3, "ok": true, "ratio": 0.5}`)
result := InterpolatePrompt(
"count={{webhook.count}} ok={{webhook.ok}} ratio={{webhook.ratio}}",
TriggerTypeWebhook,
body,
)
if result != "count=3 ok=true ratio=0.5" {
t.Errorf("unexpected coercion: %q", result)
}
}