Files
relspecgo/pkg/writers/template/safe_access_test.go
T
warkanum 495a21b67b test: expand coverage across readers, writers, cmd, ui, diff and merge
Implements tests/_plans and previously deferred packages; updates plan
README with new coverage numbers.
2026-10-03 21:33:59 +02:00

217 lines
5.6 KiB
Go

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)
}
}