Last active
August 10, 2018 13:17
-
-
Save Code-Hex/71d48d14b7fec37527d3202689dd8d7f to your computer and use it in GitHub Desktop.
Go, inteface type validation (channel and pointer of empty struct)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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