Created
February 11, 2021 16:43
-
-
Save rauljordan/7c38274a256b8e78cdfbee80d35fdd19 to your computer and use it in GitHub Desktop.
Implements proto message
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" | |
) | |
type ProtoMessage interface { | |
Hi() | |
} | |
// ImplementsProtoMessage checks if an input argument implements | |
// a proto.Message interface. This supports slices of proto messages, | |
// pointers to proto messages, structs, and maps. | |
func ImplementsProtoMessage(x interface{}) bool { | |
return implementsProtoMessageReflect(reflect.ValueOf(x)) | |
} | |
func implementsProtoMessageReflect(val reflect.Value) bool { | |
switch val.Kind() { | |
case reflect.Slice, reflect.Map: | |
return implementsProtoMessageReflect(reflect.Zero(val.Type().Elem())) | |
case reflect.Ptr, reflect.Struct: | |
modelType := reflect.TypeOf((*ProtoMessage)(nil)).Elem() | |
return val.Type().Implements(modelType) | |
default: | |
return false | |
} | |
} |
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 "testing" | |
type A struct{} | |
func (a *A) Hi() {} | |
type B struct{} | |
func (b B) Hi() {} | |
type C struct{} | |
func TestImplementsProtoMessage(t *testing.T) { | |
tests := []struct { | |
name string | |
input interface{} | |
want bool | |
}{ | |
{ | |
name: "Pointer to struct which implements proto.Message returns true", | |
input: &A{}, | |
want: true, | |
}, | |
{ | |
name: "Pointer to struct which does not implement proto.Message returns false", | |
input: &C{}, | |
want: false, | |
}, | |
{ | |
name: "Struct which implements proto.Message returns true", | |
input: B{}, | |
want: true, | |
}, | |
{ | |
name: "Struct which does not implement proto.Message returns false", | |
input: C{}, | |
want: false, | |
}, | |
{ | |
name: "Slice of slices of struct values which implement proto.Message returns true", | |
input: [][]B{{{}}}, | |
want: true, | |
}, | |
{ | |
name: "Slice of struct values which implement proto.Message returns true", | |
input: []B{{}}, | |
want: true, | |
}, | |
{ | |
name: "Empty slice of struct values which implement proto.Message returns true", | |
input: []B{}, | |
want: true, | |
}, | |
{ | |
name: "Slice of struct values which do not implement proto.Message returns false", | |
input: []C{{}}, | |
want: false, | |
}, | |
{ | |
name: "Empty slice of struct values which do not implement proto.Message returns false", | |
input: []C{}, | |
want: false, | |
}, | |
{ | |
name: "Map of value with struct type implementing proto.Message returns true", | |
input: make(map[int]B), | |
want: true, | |
}, | |
{ | |
name: "Map of value with struct type not implementing proto.Message returns false", | |
input: make(map[int]C), | |
want: false, | |
}, | |
{ | |
name: "Map of value with pointer type implementing proto.Message returns true", | |
input: make(map[int]*A), | |
want: true, | |
}, | |
{ | |
name: "Map of value with slice of pointer type implementing proto.Message returns true", | |
input: make(map[int][]*A), | |
want: true, | |
}, | |
{ | |
name: "Map of value with slice of value type implementing proto.Message returns true", | |
input: make(map[int][]B), | |
want: true, | |
}, | |
} | |
for _, tt := range tests { | |
t.Run(tt.name, func(t *testing.T) { | |
if got := ImplementsProtoMessage(tt.input); got != tt.want { | |
t.Errorf("ImplementsProtoMessage() = %v, want %v", got, tt.want) | |
} | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment