5e67d48f34
Covers Expander.Expand / ExpandStrict behaviour for object, rule, custom, and now sources, including error paths and template listing. Covers engine helpers resolveBaseDN, resolveScope, collectAttributes, buildConditionGroups, and parentDN.
138 lines
3.6 KiB
Go
138 lines
3.6 KiB
Go
package variables
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func newTestContext() *Context {
|
|
ctx := NewContext()
|
|
ctx.Now = time.Date(2025, 7, 14, 9, 30, 45, 0, time.UTC)
|
|
ctx.WithObject(map[string][]string{
|
|
"sAMAccountName": {"alice"},
|
|
"department": {"Sales"},
|
|
"mail": {"alice@example.com"},
|
|
})
|
|
ctx.WithRule("Onboard Users", "rule-123")
|
|
ctx.Custom["tenant"] = "acme"
|
|
return ctx
|
|
}
|
|
|
|
func TestExpand_ObjectAndRuleAndCustom(t *testing.T) {
|
|
e := NewExpander()
|
|
ctx := newTestContext()
|
|
|
|
got, err := e.Expand("User {{object.sAMAccountName}} in {{object.department}} (rule {{rule.name}}, tenant {{custom.tenant}})", ctx)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
want := "User alice in Sales (rule Onboard Users, tenant acme)"
|
|
if got != want {
|
|
t.Errorf("Expand mismatch:\n got: %q\nwant: %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestExpand_NowProperties(t *testing.T) {
|
|
e := NewExpander()
|
|
ctx := newTestContext()
|
|
|
|
cases := map[string]string{
|
|
"{{now.utc_date}}": "2025-07-14",
|
|
"{{now.utc_time}}": "09:30:45",
|
|
"{{now.utc_datetime}}": "2025-07-14T09:30:45Z",
|
|
"{{now.year}}": "2025",
|
|
"{{now.month}}": "07",
|
|
"{{now.day}}": "14",
|
|
"{{now.hour}}": "09",
|
|
"{{now.minute}}": "30",
|
|
}
|
|
for tmpl, want := range cases {
|
|
got, err := e.Expand(tmpl, ctx)
|
|
if err != nil {
|
|
t.Errorf("%s: unexpected error: %v", tmpl, err)
|
|
continue
|
|
}
|
|
if got != want {
|
|
t.Errorf("%s => %q, want %q", tmpl, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExpand_UnknownVariableReturnsErrorAndKeepsOriginal(t *testing.T) {
|
|
e := NewExpander()
|
|
ctx := newTestContext()
|
|
|
|
got, err := e.Expand("hello {{object.missing}}", ctx)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing object property")
|
|
}
|
|
if !strings.Contains(got, "{{object.missing}}") {
|
|
t.Errorf("expected original placeholder preserved, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestExpandStrict_FailsOnUnresolved(t *testing.T) {
|
|
e := NewExpander()
|
|
ctx := newTestContext()
|
|
|
|
_, err := e.Expand("{{unknownSource.foo}}", ctx)
|
|
if err == nil {
|
|
t.Fatal("expected Expand to surface error for unknown source")
|
|
}
|
|
|
|
_, err = e.ExpandStrict("{{object.missing}}", ctx)
|
|
if err == nil {
|
|
t.Fatal("expected ExpandStrict to fail on missing property")
|
|
}
|
|
}
|
|
|
|
func TestExpand_NoVariables(t *testing.T) {
|
|
e := NewExpander()
|
|
ctx := newTestContext()
|
|
got, err := e.Expand("plain text", ctx)
|
|
if err != nil || got != "plain text" {
|
|
t.Errorf("got (%q, %v), want (\"plain text\", nil)", got, err)
|
|
}
|
|
}
|
|
|
|
func TestExpand_InvalidPath(t *testing.T) {
|
|
e := NewExpander()
|
|
ctx := newTestContext()
|
|
_, err := e.Expand("{{object}}", ctx)
|
|
if err == nil {
|
|
t.Fatal("expected error for variable without source.property format")
|
|
}
|
|
}
|
|
|
|
func TestListVariables_DedupesAndPreservesOrder(t *testing.T) {
|
|
e := NewExpander()
|
|
got := e.ListVariables("{{object.a}} and {{object.b}} and {{object.a}}")
|
|
if len(got) != 2 {
|
|
t.Fatalf("expected 2 unique variables, got %d (%v)", len(got), got)
|
|
}
|
|
if got[0] != "{{object.a}}" || got[1] != "{{object.b}}" {
|
|
t.Errorf("unexpected order: %v", got)
|
|
}
|
|
}
|
|
|
|
func TestValidateTemplate_MismatchedDelimiters(t *testing.T) {
|
|
e := NewExpander()
|
|
warnings := e.ValidateTemplate("{{object.foo}")
|
|
if len(warnings) == 0 {
|
|
t.Fatal("expected a warning for mismatched delimiters")
|
|
}
|
|
if len(e.ValidateTemplate("{{object.foo}}")) != 0 {
|
|
t.Fatal("expected no warnings for balanced delimiters")
|
|
}
|
|
}
|
|
|
|
func TestWithObject_UsesFirstValue(t *testing.T) {
|
|
ctx := NewContext().WithObject(map[string][]string{
|
|
"memberOf": {"CN=A,DC=x", "CN=B,DC=x"},
|
|
})
|
|
if ctx.Object["memberOf"] != "CN=A,DC=x" {
|
|
t.Errorf("expected first value retained, got %q", ctx.Object["memberOf"])
|
|
}
|
|
}
|