Fixed MIssingStructField panic

This commit is contained in:
porosnicuadrian
2021-08-02 11:04:52 +03:00
committed by Dan Christian Bogos
parent 690504f14a
commit b7a442083c
2 changed files with 62 additions and 8 deletions

View File

@@ -24,18 +24,41 @@ import (
"strings"
)
func fieldByIndexIsEmpty(v reflect.Value, index []int) bool {
if len(index) == 1 {
return valueIsEmpty(v.Field(index[0]))
}
for i, x := range index {
if i > 0 {
if v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
if v.IsNil() {
return true
}
v = v.Elem()
}
}
v = v.Field(x)
}
return valueIsEmpty(v)
}
func valueIsEmpty(fld reflect.Value) bool {
if fld.Kind() == reflect.String && fld.CanSet() {
fld.SetString(strings.TrimSpace(fld.String()))
}
return (fld.Kind() == reflect.String && fld.String() == EmptyString) ||
((fld.Kind() == reflect.Slice || fld.Kind() == reflect.Map) && fld.Len() == 0) ||
(fld.Kind() == reflect.Int && fld.Int() == 0)
}
// Detects missing field values based on mandatory field names, s should be a pointer to a struct
func MissingStructFields(s interface{}, mandatories []string) []string {
missing := []string{}
sValue := reflect.ValueOf(s).Elem()
sType := sValue.Type()
for _, fieldName := range mandatories {
fld := reflect.ValueOf(s).Elem().FieldByName(fieldName)
// sanitize the string fields before checking
if fld.Kind() == reflect.String && fld.CanSet() {
fld.SetString(strings.TrimSpace(fld.String()))
}
if (fld.Kind() == reflect.String && fld.String() == "") ||
((fld.Kind() == reflect.Slice || fld.Kind() == reflect.Map) && fld.Len() == 0) ||
(fld.Kind() == reflect.Int && fld.Int() == 0) {
fldStr, ok := sType.FieldByName(fieldName)
if !ok || fieldByIndexIsEmpty(sValue, fldStr.Index){
missing = append(missing, fieldName)
}
}

View File

@@ -35,6 +35,37 @@ func TestMissingStructFieldsCorrect(t *testing.T) {
}
}
func TestMissingStructFieldsNilCorporate(t *testing.T) {
tst := &TenantIDWithAPIOpts{
APIOpts: map[string]interface{}{
OptsAPIKey: "attr1234",
},
}
if missing := MissingStructFields(tst,
[]string{Tenant}); len(missing) != 1 {
t.Errorf("TenantIDWithAPIOpts is missing from my struct: %v", missing)
}
}
func TestMissingStructFieldsNilCorporateTwoStructs(t *testing.T) {
tst := &struct {
APIOpts map[string]interface{}
*TenantID
*TenantWithAPIOpts
}{
APIOpts: map[string]interface{}{
OptsAPIKey: "attr1234",
},
TenantID: &TenantID{
Tenant: "cgrates.org",
},
}
if missing := MissingStructFields(tst,
[]string{Tenant}); len(missing) != 1 {
t.Errorf("TenantIDWithAPIOpts is missing from my struct: %v", missing)
}
}
func TestUpdateStructWithIfaceMap(t *testing.T) {
type myStruct struct {
String string