Skip to content

Instantly share code, notes, and snippets.

@Code-Hex
Last active August 10, 2018 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Code-Hex/71d48d14b7fec37527d3202689dd8d7f to your computer and use it in GitHub Desktop.
Save Code-Hex/71d48d14b7fec37527d3202689dd8d7f to your computer and use it in GitHub Desktop.
Go, inteface type validation (channel and pointer of empty struct)
package main
import (
"reflect"
"testing"
)
type TS struct {
id int
name string
}
type TestStruct struct {
Str string
Int int
Float64 float64
Slice []complex128
Bool bool
Uint uint
Ary [2]string
Value TS
Pointer *TS
SliceTestStruct []*TS
MapTestStruct map[string][]*TS
}
func TestValidateEmptyStructValue(t *testing.T) {
testcases := []struct {
name string
typ interface{}
wantErr string
unexpectedErr bool
}{
{
name: "valid struct pointer",
typ: &TestStruct{},
},
{
name: "struct value",
typ: &TestStruct{},
wantErr: "must pass a empty struct pointer",
},
{
name: "int",
typ: 10,
wantErr: "must pass a empty struct pointer",
},
{
name: "string",
typ: "10",
wantErr: "must pass a empty struct pointer",
},
{
name: "nil",
typ: nil,
wantErr: "must pass a empty struct pointer",
},
{
name: "non empty struct (string)",
typ: &TestStruct{Str: "Hello"},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (int)",
typ: &TestStruct{Int: 10},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (float64)",
typ: &TestStruct{Float64: 30.5},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct ([]complex128])",
typ: &TestStruct{Slice: []complex128{-23, 1i}},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (bool)",
typ: &TestStruct{Bool: true},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (array)",
typ: &TestStruct{Ary: [2]string{}},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (struct value)",
typ: &TestStruct{Value: TS{id: 1}},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (struct pointer)",
typ: &TestStruct{Pointer: &TS{}},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (slice of struct pointer)",
typ: &TestStruct{SliceTestStruct: make([]*TS, 1)},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
{
name: "non empty struct (map of slice of struct pointer)",
typ: &TestStruct{MapTestStruct: make(map[string][]*TS, 1)},
wantErr: "must pass a empty struct pointer, you passed containing values",
},
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
v := reflect.ValueOf(testcase.typ)
err := validateEmptyStructValue(v)
if err != nil {
if err.Error() != testcase.wantErr {
t.Fatalf(`expected "%s", but got "%s"`, testcase.wantErr, err)
}
}
})
}
}
func Test_validateSendChannel(t *testing.T) {
testcases := []struct {
name string
typ interface{}
wantErr string
}{
{
name: "channel",
typ: make(chan struct{}),
},
{
name: "send channel",
typ: make(chan<- struct{}),
},
{
name: "another type",
typ: 10,
wantErr: `must pass a channel which is send direction (got "int")`,
},
{
name: "nil",
typ: nil,
wantErr: `must pass a channel which is send direction (got "nil")`,
},
{
name: "recv channel",
typ: make(<-chan struct{}),
wantErr: "must pass a channel which is send direction",
},
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
v := reflect.ValueOf(testcase.typ)
err := validateSendChannel(v)
if err != nil {
if err.Error() != testcase.wantErr {
t.Fatalf(`expected "%s", but got "%s"`, testcase.wantErr, err)
}
}
})
}
}
package main
import (
"errors"
"fmt"
"reflect"
)
func validateEmptyStructValue(v reflect.Value) error {
if !v.IsValid() || v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
return errors.New("must pass a empty struct pointer")
}
if !isZero(v) {
return errors.New("must pass a empty struct pointer, you passed containing values")
}
return nil
}
func validateSendChannel(chrv reflect.Value) error {
if !chrv.IsValid() || chrv.Kind() != reflect.Chan {
typ := "nil"
if chrv.IsValid() {
typ = chrv.Type().String()
}
return fmt.Errorf(`must pass a channel which is send direction (got "%s")`, typ)
}
if (chrv.Type().ChanDir() & reflect.SendDir) == 0 {
return errors.New(`must pass a channel which is send direction`)
}
return nil
}
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return v.Bool() == false
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() == 0
case reflect.Ptr, reflect.Interface:
return !v.IsNil()
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if !isZero(v.Index(i)) {
return false
}
}
return true
case reflect.Slice, reflect.String, reflect.Map:
return v.Len() == 0
case reflect.Struct:
for i, n := 0, v.NumField(); i < n; i++ {
if !isZero(v.Field(i)) {
return false
}
}
return true
}
return false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment