Check if ast.Expr Implements Interface in Go - go

Is there any way we can check if any ast.Expr is implementing interface like fmt.Stringer?
I found this function types.Implements() can be used here but, I am not sure how I can create types.Interface out of an existing interface type, like fmt.Stringer, which is required for types.Implements() function.
I am looking for a function implementation like this:
func isStringer(ti *types.Info, obj ast.Expr) bool {
panic("not implemented")
}
Workaround I am using currently:
func isStringer(ti *types.Info, obj ast.Expr) bool {
t := ti.TypeOf(obj).(*types.Named)
for i := 0; i < t.NumMethods(); i++ {
if t.Method(i).Type().(*types.Signature).String() == "func() string" {
return true
}
}
return false
}

The usual way I check if an interface is implemented is by using a long form type assertion
Ex:
func isStringer(obj ast.Expr) bool {
_, ok := obj.(fmt.Stringer)
return ok
}
What's going on here is that when we provide a second variable to the type assertion (usually named ok by convention), go will not panic if the type cannot be cast, instead it will set ok = false.
We can then simply return the value of ok and be assured that if ok == true the obj implements stringer and if ok == false it does not.
If we want to use the methods provided by the stringer interface, we can return the cast variable as well:
func isStringer(obj ast.Expr) (fmt.Stringer, bool) {
return obj.(fmt.Stringer)
}

Related

Go interface to enforce same argument type between methods (but can be any type)

The title is confusing, I'm sure, but it's hard to describe what I mean.
I want to create a Go interface that has two methods; the first one returns a value, and the second one accepts a value. I want to ensure that method 1 returns the same type as method 2 accepts, without specifying what the type is (other than it being a struct). For example:
type MyInterface interface {
Method1() MyType
Method2(MyType) error
}
Where MyType can be any type (of struct), as long as it's the same in both Method 1 and Method 2.
Is there any way to do this in Go?
EDIT:
Based on #iLoveReflection's answer, I've tried the following:
package main
type MyInterface interface {
GetType() interface{}
UseType(input interface{})
}
type MyImplementation struct{}
type MyType struct {
}
func (i MyImplementation) GetType() MyType {
return MyType{}
}
func (i MyImplementation) UseType(input MyType) {
return
}
func test(input MyInterface) {
return
}
func assertArgAndResult() {
var v MyImplementation
v.UseType(v.GetType())
}
func main() {
test(MyImplementation{})
}
So basically, I'm specifying an interface (MyInterface), and I want to ensure that a given implementation of that interface (MyImplementation, which would be created by the user of my package) meets the requirement stated in the original post.
assertArgAndResult() is working as expected, and ensures that MyImplementation meets the requirements. However, I get a compile error in the main() function:
cannot use MyImplementation literal (type MyImplementation) as type MyInterface in argument to test:
MyImplementation does not implement MyInterface (wrong type for GetType method)
have GetType() MyType
want GetType() interface {}
Add the following function to a package to ensure that the input and output types match at compile time:
func assertArgAndResult() {
var v MyInterface
v.Method2(v.Method1())
}
This function will not be included in the executable as long as the function is not called.
There is no compile time check that will ensure that MyType is a struct type as specified in the question.
The reflect package can be used to check type types completely.
// checkItf returns true of the interface value pointed to by
// pi has Method1 with some return type T and Method2 with
// argument type T.
func checkItf(pi interface{}) bool {
t := reflect.TypeOf(pi)
if t.Kind() != reflect.Ptr {
return false // or handle as error
}
t = t.Elem()
if t.Kind() != reflect.Interface {
return false // or handle as error
}
m1, ok := t.MethodByName("Method1")
// Method1 should have no outputs and one input.
if !ok || m1.Type.NumIn() != 0 || m1.Type.NumOut() != 1 {
return false
}
// Method2 should have one input and one output.
m2, ok := t.MethodByName("Method2")
if !ok || m2.Type.NumIn() != 1 || m2.Type.NumOut() != 1 {
return false
}
e := reflect.TypeOf((*error)(nil)).Elem()
s := m1.Type.Out(0)
// The type must be a struct and
// the input type of Method2 must be the same as the output of Method1 and
// Method2 must return error.
return s.Kind() == reflect.Struct &&
m2.Type.In(0) == s &&
m2.Type.Out(0) == e
}
Call it like this:
func init() {
if !checkItf((*MyInterface)(nil)) {
panic("mismatched argument and return time son MyInterface")
}
}

Return polymorphic type with data member

I'm trying to write a function getTargetServer() to return a polymorphic type that has both a data member URL and a method Close(). This would be a generalization of the *Server returned from httptest.NewServer() but I want to alternatively be able to return a custom type for which Close() is a NOP.
type externalTestServer struct {
URL string
}
func (externalTestServer) Close() {}
func getTargetServer() *externalTestServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return &externalTestServer{URL: urlbase}
} else {
testServer := httptest.NewServer(newMyServerHandler())
// return testServer // ### Error ###
return &externalTestServer{URL: testServer.URL}
}
}
func Test_health_check(t *testing.T) {
testServer := getTargetServer()
defer testServer.Close()
response, err := http.Get(testServer.URL + "/health")
assert.NilError(t, err)
assert.Assert(t, cmp.Equal(response.StatusCode, http.StatusOK))
}
This works like a charm except that Close() is always a NOP. When I uncomment the indicated ### Error ### line in order to return a closable *Server, I get the following error message:
cannot use testServer (type *httptest.Server) as type *externalTestServer in return argument
I understand the error, but haven't discovered a solution that lets me return a polymorphic type that generalizes *Server
Note: "A Tour of Go" defines an interface type as follows:
An interface type is defined as a set of method signatures.
Therefore, returning a simple interface will not allow for directly-accessible data members.
You could create a struct that has a field which is a string URL and a field that is a Close func. The Close func can be implemented by either externalTestServer or httptest.Server:
type server struct {
URL string
Close func()
}
if urlbase, ok := optionals["urlbase"].(string); ok {
extServer := &externalTestServer{URL: urlbase}
return &server{
URL: urlbase,
Close: extServer.Close,
}
}
testServer := httptest.NewServer(newMyServerHandler())
return &server{
URL: testServer.URL,
Close: testServer.Close,
}
http.Server is a struct, so you cannot return a polymorphic object that generalizes that. You can do something else though:
type Server interface {
GetURL() string
Close() error
}
type testServer struct {
URL string
}
func (t testServer) Close() error {}
func (t testServer) GetURL() string {return t.URL}
type httpServer struct {
*http.Server
}
func (t httpServer) GetURL() string { return the url }
You can then return Server from your function.
Chris Drew's approach is ideal for this specific case, because it requires minimal code overhead. Put another way, it is the simplest thing that will solve today's problem. The solution uses the magic of an implicit closure (for the receiver) to reference the implementation of Close() polymorphically.
My slightly simplified version of that is here...
type genericServer struct {
URL string // snapshot of internal data
Close func() // single-function polymorphism without 'interface'
}
func getTargetServer() genericServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return genericServer{URL: urlbase, Close: func() {}}
}
testServer := httptest.NewServer(newMyServerHandler())
return genericServer{URL: testServer.URL, Close: testServer.Close}
}
By embedding an actual interface type into to return struct, this concept can be seamlessly extended to better support non-trivial polymorphic interfaces. In this case, the Polymorphism is explicit based on the internal use of an interface type. Still, the returned type is a wrapper that includes a copy of the (constant) member data, so the usage is identical -- effectively generalizing that of *Server for this use-case.
type Server interface {
Close()
}
type nopServer struct {
}
func (nopServer) Close() {}
type genericServer struct {
URL string // snapshot of specific data
Server // embedded interface type for explicit polymorphism
}
func getTargetServer() genericServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return genericServer{URL: urlbase, Server: nopServer{}}
}
testServer := httptest.NewServer(newMyServerHandler())
return genericServer{URL: testServer.URL, Server: testServer}
}
Note that the URL value is not a live member of the implementation, so these solutions, as presented, are only meaningful when the data value will not change, although perhaps that limitation could be overcome by using a pointer.

How to test dependency has been called correctly

In Go, how would I test that a mock dependency has been called in the correct way.
If I have a struct that takes a interface for a dependency, after injection I want to be able to test the original mock object has been called.
My current code in this example I can not see that the struct value has changed. If I change my code to pass by reference it triggers the error:
s.simpleInterface.Call undefined (type *SimpleInterface is pointer to interface, not interface)
type SimpleInterface interface {
Call()
}
type Simple struct {
simpleInterface SimpleInterface
}
func (s Simple) CallInterface() {
s.simpleInterface.Call()
}
type MockSimple struct {
hasBeenCalled bool
}
func (ms MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
I see three easy ways to fix this:
1- Change the signature of the Call method to receive a pointer to MockSimple, and when instantiating the Simple struct, give it the address of your mock:
func (ms *MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: &ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
2- Not the cleanest solution, but still works. Use it if you really cant use #1. Declare "hasBeenCalled" somewhere else and change your MockSimple to hold a pointer to it:
type MockSimple struct {
hasBeenCalled *bool
}
func (ms MockSimple) Call() {
*ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
hasBeenCalled := false
ms := MockSimple{&hasBeenCalled}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
3- Probably a really bad solution: using globals, so I would only use it as a last resort (always avoid global state). Make "hasBeenCalled" a global and modify it from the method.
var hasBeenCalled bool
type MockSimple struct{}
func (ms MockSimple) Call() {
hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
Cheers!

How to check if a value implements an interface

I want to compare my type by the specific way. For this purpose, I create the function MyType.Same(other MyType) bool for each type.
In some generic function, I want to check if the parameter has a function "Same" and invoke it if yes.
How can I do it in a generic way for different types?
type MyType struct {
MyField string
Id string // ignored by comparison
}
func (mt MyType) Same(other MyType) bool {
return mt.MyField == other.MyField
}
// MyOtherType... Same(other MyOtherType)
type Comparator interface {
Same(Camparator) bool // or Same(interface{}) bool
}
myType = new(MyType)
_, ok := reflect.ValueOf(myType).Interface().(Comparator) // ok - false
myOtherType = new(myOtherType)
_, ok := reflect.ValueOf(myOtherType).Interface().(Comparator) // ok - false
The types do not satisfy the Comparator interface. The types have a Same method, but those methods do not have argument type Comparator. The argument types must match to satisfy an interface.
Change the the methods and interface to take the same argument type. Use a type assertion to check that receiver and argument have the same type and to get argument as the receiver's type.
type Comparator interface {
Same(interface{}) bool
}
func (mt MyType) Same(other interface{}) bool {
mtOther, ok := other.(MyType)
if !ok {
return false
}
return return mt.MyField == mtOther.MyField
}
Use the following to compare two values:
func same(a, b interface{}) bool {
c, ok := a.(Comparator)
if !ok {
return false
}
return c.Same(b)
}
If the types the application works with have the Compare method, then there's no need to declare the Comparator interface or use the same function in the previous snippet of code. For example, the Comparator interface is not required for the following:
var mt MyType
var other interface{}
eq := mt.Same(other)

How to dump methods of structs in Golang?

The Golang "fmt" package has a dump method called Printf("%+v", anyStruct). I'm looking for any method to dump a struct and its methods too.
For example:
type Foo struct {
Prop string
}
func (f Foo)Bar() string {
return f.Prop
}
I want to check the existence of the Bar() method in an initialized instance of type Foo (not only properties).
Is there any good way to do this?
You can list the methods of a type using the reflect package. For example:
fooType := reflect.TypeOf(&Foo{})
for i := 0; i < fooType.NumMethod(); i++ {
method := fooType.Method(i)
fmt.Println(method.Name)
}
You can play around with this here: http://play.golang.org/p/wNuwVJM6vr
With that in mind, if you want to check whether a type implements a certain method set, you might find it easier to use interfaces and a type assertion. For instance:
func implementsBar(v interface{}) bool {
type Barer interface {
Bar() string
}
_, ok := v.(Barer)
return ok
}
...
fmt.Println("Foo implements the Bar method:", implementsBar(Foo{}))
Or if you just want what amounts to a compile time assertion that a particular type has the methods, you could simply include the following somewhere:
var _ Barer = Foo{}

Resources