package template import ( "reflect" "testing" ) type accessItem struct { Name string ID int } func TestGetAndGetOr(t *testing.T) { m := map[string]interface{}{"a": 1, "nilv": nil} if got := Get(m, "a"); got != 1 { t.Errorf("Get: %v", got) } if got := Get(m, "missing"); got != nil { t.Errorf("Get missing: %v", got) } if got := Get(nil, "a"); got != nil { t.Errorf("Get nil map: %v", got) } if got := GetOr(m, "missing", "def"); got != "def" { t.Errorf("GetOr missing: %v", got) } if got := GetOr(m, "nilv", "def"); got != "def" { t.Errorf("GetOr nil value: %v", got) } if got := GetOr(m, "a", "def"); got != 1 { t.Errorf("GetOr present: %v", got) } } func TestGetPath(t *testing.T) { cfg := map[string]interface{}{ "db": map[string]interface{}{"conn": map[string]interface{}{"host": "h"}}, } if got := GetPath(cfg, "db.conn.host"); got != "h" { t.Errorf("GetPath: %v", got) } if got := GetPath(cfg, "db.nope.host"); got != nil { t.Errorf("GetPath missing: %v", got) } if got := GetPathOr(cfg, "db.nope", "dflt"); got != "dflt" { t.Errorf("GetPathOr: %v", got) } if got := GetPathOr(cfg, "db.conn.host", "dflt"); got != "h" { t.Errorf("GetPathOr present: %v", got) } if !HasPath(cfg, "db.conn") || HasPath(cfg, "db.x") || HasPath(nil, "a") { t.Errorf("HasPath mismatch") } } func TestSafeIndex(t *testing.T) { s := []string{"a", "b"} if got := SafeIndex(s, 1); got != "b" { t.Errorf("SafeIndex: %v", got) } for _, i := range []int{-1, 2, 99} { if got := SafeIndex(s, i); got != nil { t.Errorf("SafeIndex(%d) must be nil, got %v", i, got) } } if got := SafeIndex("notslice", 0); got != nil { t.Errorf("non-slice: %v", got) } if got := SafeIndexOr(s, 5, "d"); got != "d" { t.Errorf("SafeIndexOr: %v", got) } if got := SafeIndexOr(s, 0, "d"); got != "a" { t.Errorf("SafeIndexOr present: %v", got) } } func TestHas(t *testing.T) { m := map[string]int{"a": 1} var nilPtr *map[string]int tests := []struct { name string m interface{} key interface{} want bool }{ {"present", m, "a", true}, {"missing", m, "b", false}, {"pointer to map", &m, "a", true}, {"nil pointer", nilPtr, "a", false}, {"non-map", []int{1}, 0, false}, {"nil", nil, "a", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := Has(tt.m, tt.key); got != tt.want { t.Errorf("got %v", got) } }) } } func TestKeysValues(t *testing.T) { m := map[string]int{"a": 1, "b": 2} if got := Keys(m); len(got) != 2 { t.Errorf("Keys: %v", got) } if got := Values(m); len(got) != 2 { t.Errorf("Values: %v", got) } if got := Keys(nil); len(got) != 0 { t.Errorf("Keys nil: %v", got) } if got := Values(5); len(got) != 0 { t.Errorf("Values non-map: %v", got) } } func TestMerge(t *testing.T) { m1 := map[string]int{"a": 1, "b": 2} m2 := map[string]int{"b": 3, "c": 4} var nilPtr *map[string]int got := Merge(m1, &m2, nilPtr, nil, 5) want := map[interface{}]interface{}{"a": 1, "b": 3, "c": 4} if !reflect.DeepEqual(got, want) { t.Errorf("got %v", got) } if got := Merge(); len(got) != 0 { t.Errorf("empty merge: %v", got) } } func TestPickOmit(t *testing.T) { m := map[string]int{"a": 1, "b": 2, "c": 3} var nilPtr *map[string]int if got := Pick(m, "a", "z"); !reflect.DeepEqual(got, map[interface{}]interface{}{"a": 1}) { t.Errorf("Pick: %v", got) } if got := Pick(&m, "b"); len(got) != 1 { t.Errorf("Pick ptr: %v", got) } if got := Pick(nilPtr, "a"); len(got) != 0 { t.Errorf("Pick nil ptr: %v", got) } if got := Pick(5, "a"); len(got) != 0 { t.Errorf("Pick non-map: %v", got) } if got := Omit(m, "a", "z"); !reflect.DeepEqual(got, map[interface{}]interface{}{"b": 2, "c": 3}) { t.Errorf("Omit: %v", got) } if got := Omit(&m); len(got) != 3 { t.Errorf("Omit ptr: %v", got) } if got := Omit(nilPtr, "a"); len(got) != 0 { t.Errorf("Omit nil ptr: %v", got) } if got := Omit("x", "a"); len(got) != 0 { t.Errorf("Omit non-map: %v", got) } } func TestSliceContainsIndexOf(t *testing.T) { s := []string{"a", "b", "c"} sp := &s var nilPtr *[]string if !SliceContains(s, "b") || SliceContains(s, "z") { t.Errorf("SliceContains") } if !SliceContains(sp, "c") || !SliceContains([2]int{1, 2}, 2) { t.Errorf("SliceContains ptr/array") } if SliceContains(nilPtr, "a") || SliceContains("str", "s") || SliceContains(nil, 1) { t.Errorf("SliceContains invalid input") } if got := IndexOf(s, "c"); got != 2 { t.Errorf("IndexOf: %d", got) } if got := IndexOf(sp, "a"); got != 0 { t.Errorf("IndexOf ptr: %d", got) } for _, in := range []interface{}{s, nilPtr, "str", nil} { if got := IndexOf(in, "zzz"); got != -1 { t.Errorf("IndexOf miss %v: %d", in, got) } } } func TestPluck(t *testing.T) { items := []*accessItem{{"a", 1}, nil, {"c", 3}} got := Pluck(items, "Name") if !reflect.DeepEqual(got, []interface{}{"a", nil, "c"}) { t.Errorf("struct ptrs: %v", got) } if got := Pluck([]accessItem{{"a", 1}}, "Missing"); !reflect.DeepEqual(got, []interface{}{nil}) { t.Errorf("missing field: %v", got) } maps := []map[string]int{{"k": 1}, {"x": 2}} if got := Pluck(maps, "k"); !reflect.DeepEqual(got, []interface{}{1, nil}) { t.Errorf("maps: %v", got) } if got := Pluck([]int{1, 2}, "k"); !reflect.DeepEqual(got, []interface{}{nil, nil}) { t.Errorf("scalars: %v", got) } var nilPtr *[]accessItem if got := Pluck(nilPtr, "Name"); len(got) != 0 { t.Errorf("nil ptr: %v", got) } if got := Pluck("str", "Name"); len(got) != 0 { t.Errorf("non-slice: %v", got) } s := []accessItem{{"z", 9}} if got := Pluck(&s, "ID"); !reflect.DeepEqual(got, []interface{}{9}) { t.Errorf("ptr to slice: %v", got) } }