Skip to content

Commit

Permalink
introducing no field is empty assertion
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterEFinch committed Apr 26, 2024
1 parent 8d4dcbb commit 621db53
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 0 deletions.
8 changes: 8 additions & 0 deletions assert/assertion_format.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions assert/assertion_forward.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions assert/assertions.go
Expand Up @@ -2107,3 +2107,38 @@ func buildErrorChainString(err error) string {
}
return chain
}

// NoFieldIsEmpty asserts that object, which must be a struct or eventually reference to one, has no empty exported fields.
func NoFieldIsEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if reflect.TypeOf(object).Kind() == reflect.Ptr {
return NoFieldIsEmpty(t, reflect.ValueOf(object).Elem().Interface(), msgAndArgs)
}

if h, ok := t.(tHelper); ok {
h.Helper()
}

objectType := reflect.TypeOf(object)
if objectType.Kind() != reflect.Struct {
return Fail(t, "Input must be a struct or eventually reference one", msgAndArgs...)
}

var emptyFields []string
objectValue := reflect.ValueOf(object)
for i := 0; i < objectType.NumField(); i++ {
field := objectType.Field(i)
if !field.IsExported() {
continue
}

if isEmpty(objectValue.Field(i).Interface()) {
emptyFields = append(emptyFields, field.Name)
}
}

if len(emptyFields) > 0 {
return Fail(t, fmt.Sprintf("Object contained empty fields: %s", strings.Join(emptyFields, ", ")), msgAndArgs...)
}

return true
}
85 changes: 85 additions & 0 deletions assert/assertions_test.go
Expand Up @@ -3228,3 +3228,88 @@ func TestErrorAs(t *testing.T) {
})
}
}

func TestNoFieldIsEmpty(t *testing.T) {
str := "a string"
tests := []struct {
name string
input interface{}
result bool
resultErrMsg string
}{
{
name: "success",
input: struct {
Float64 float64
Func func()
Int int
Interface interface{}
Pointer *string
Slice []string
String string
Struct struct{ String string }
}{
Float64: 1.5,
Func: func() {},
Int: 1,
Interface: "interface",
Pointer: &str,
Slice: []string{"a", "b"},
String: "a string",
Struct: struct{ String string }{String: "a nested string"},
},
result: true,
},
{
name: "success_pointer",
input: &struct {
String string
}{
String: "a string",
},
result: true,
},
{
name: "success_unexported",
input: struct{ unexported string }{},
result: true,
},
{
name: "failure",
input: struct {
Float64 float64
Func func()
Int int
Interface interface{}
Pointer *string
Slice []string
String string
Struct struct{ String string }
}{},
result: false,
resultErrMsg: "Object contained empty fields: Float64, Func, Int, Interface, Pointer, Slice, String, Struct\n",
},
{
name: "failure_partial",
input: struct {
StringA string
StringB string
}{StringA: "not_empty"},
result: false,
resultErrMsg: "Object contained empty fields: StringB\n",
},
{
name: "failure_wrong_type",
input: "a string is not a struct",
result: false,
resultErrMsg: "Input must be a struct or eventually reference one\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockT := new(captureTestingT)
result := NoFieldIsEmpty(mockT, tt.input)
mockT.checkResultAndErrMsg(t, tt.result, result, tt.resultErrMsg)
})
}
}
22 changes: 22 additions & 0 deletions require/require.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions require/require_forward.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 621db53

Please sign in to comment.