This is a random example that accepts a pointer struct type, iterates through all its fields and returns an error as soon as it finds a nil value. A zero value is not considered as a nil!


package util

import (
"errors"
"fmt"
"reflect"
)

func CheckNilValuePresence(input any, ignore map[string]struct{}) error {
object := reflect.ValueOf(input)
if object.Kind() != reflect.Ptr {
return errors.New(("input must be a pointer")
}

object = object.Elem()
if object.Kind() != reflect.Struct {
return errors.New("input must be a struct")
}

typ := object.Type()

for i := 0; i < object.NumField(); i++ {
name := typ.Field(i).Name
value := object.FieldByName(name)
kind := object.Field(i).Kind()

// If the field is meant to be ignored.
if _, ok := ignore[name]; ok {
continue
}

// If the field is an interface type and underlying value is nil.
if kind == reflect.Interface && value.IsNil() {
return fmt.Errorf("the %s field is nil", name)
}

// If the field is not a pointer type its value cannot be nil, or if a
// non-pointer fields value is not nil.
if kind != reflect.Pointer || !value.IsNil() {
continue
}

return fmt.Errorf("the %s field is nil", name)
}

return nil
}

package util

import (
"errors"
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

type testDriver interface{ drive() }

type testCar struct{}

func (testCar) drive() {}

type testObject struct {
FieldInt int
FieldIntP *int
FieldStr string
FieldStrP *string
FieldBool bool
FieldBoolP *bool
FieldSlice []string
FieldSliceP *[]string
FieldMap map[string]string
FieldMapP *map[string]string
FieldAnonStruct struct{}
FieldAnonStructP *struct{}
FieldInterface interface{}
FieldInterfaceP *interface{}
FieldTime time.Time
FieldTimeP *time.Time
FieldDriverInterface testDriver
FieldCarStruct testCar
FieldCarStructP *testCar
}

func Test_CheckNilValuePresence(t *testing.T) {
// Checking if the input is a pointer.
assert.Equal(t, CheckNilValuePresence(testCar{}, nil), fmt.Errorf("input must be a pointer"))

// Checking if the input is a struct type.
input := "not-a-struct"
assert.Equal(t, CheckNilValuePresence(&input, nil), errors.New("input must be a struct"))

// Explicitly ignoring all nillable fields even though they all are nil.
ignore := map[string]struct{}{
"FieldIntP": {},
"FieldStrP": {},
"FieldBoolP": {},
"FieldSliceP": {},
"FieldMapP": {},
"FieldAnonStructP": {},
"FieldInterface": {},
"FieldInterfaceP": {},
"FieldTimeP": {},
"FieldCarStructP": {},
}
assert.NoError(t, CheckNilValuePresence(&testCar{}, ignore))

// All the rest table driven tests cases.
fieldIntP := 123
fieldStrP := "string"
fieldBoolP := true
fieldSliceP := []string{"slice"}
fieldMapP := map[string]string{"map": "map"}
fieldTimeP := time.Now()
fieldInterface := "interface{}"
//nolint: gosimple
var fieldInterfaceP interface{}
fieldInterfaceP = "interface{}"

tests := []struct {
name string
input *testObject
error error
}{
{
name: "nil int pointer field",
input: &testObject{},
error: errors.New("the FieldIntP field is nil"),
},
{
name: "nil string pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
},
error: errors.New("the FieldStrP field is nil"),
},
{
name: "nil bool pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
},
error: errors.New("the FieldBoolP field is nil"),
},
{
name: "nil slice pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
},
error: errors.New("the FieldSliceP field is nil"),
},
{
name: "nil map pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
},
error: errors.New("the FieldMapP field is nil"),
},
{
name: "nil anon struct pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
},
error: errors.New("the FieldAnonStructP field is nil"),
},
{
name: "nil time pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
FieldAnonStructP: &struct{}{},
},
error: errors.New("the FieldInterface field is nil"),
},
{
name: "nil interface field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
FieldAnonStructP: &struct{}{},
FieldInterface: fieldInterface,
},
error: errors.New("the FieldInterfaceP field is nil"),
},
{
name: "nil interface pointer field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
FieldTimeP: &fieldTimeP,
FieldAnonStructP: &struct{}{},
FieldInterface: fieldInterface,
},
error: errors.New("the FieldInterfaceP field is nil"),
},
{
name: "nil interface field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
FieldTimeP: &fieldTimeP,
FieldAnonStructP: &struct{}{},
FieldInterface: fieldInterface,
FieldInterfaceP: &fieldInterfaceP,
},
error: errors.New("the FieldDriverInterface field is nil"),
},
{
name: "nil typed struct interface field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
FieldTimeP: &fieldTimeP,
FieldAnonStructP: &struct{}{},
FieldInterface: fieldInterface,
FieldInterfaceP: &fieldInterfaceP,
FieldDriverInterface: testCar{},
},
error: errors.New("the FieldCarStructP field is nil"),
},
{
name: "nil interface pinter field",
input: &testObject{
FieldIntP: &fieldIntP,
FieldStrP: &fieldStrP,
FieldBoolP: &fieldBoolP,
FieldSliceP: &fieldSliceP,
FieldMapP: &fieldMapP,
FieldTimeP: &fieldTimeP,
FieldAnonStructP: &struct{}{},
FieldInterface: fieldInterface,
FieldInterfaceP: &fieldInterfaceP,
FieldDriverInterface: testCar{},
FieldCarStructP: &testCar{},
},
error: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := CheckNilValuePresence(test.input, nil)
assert.Equal(t, test.error, err)
})
}
}