Short
The following code does not exactly do what expected:
https://play.golang.org/p/sO4w4I_Lle
I assume that I mess up some pointer/reference stuff as usual, however I expect my...
func unmarshalJSON(in []byte, s interface{}) error
... and encoding/jsons...
func Unmarshal(data []byte, v interface{}) error
...to behave the same way (eg. update the referenced passed as second argument).
Long
The example above is a minimal reproducer that does not make much sense. This is in order to make it work on the playground. However, an less minimal example that does make sense is this:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
func unmarshalYAML(in []byte, s interface{}) error {
var result map[interface{}]interface{}
err := yaml.Unmarshal(in, &result)
s = cleanUpInterfaceMap(result)
// s is printed as expected
fmt.Println(s) // map[aoeu:[test aoeu] oaeu:[map[mahl:aoec tase:aoeu]]]
return err
}
func cleanUpInterfaceArray(in []interface{}) []interface{} {
out := make([]interface{}, len(in))
for i, v := range in {
out[i] = cleanUpMapValue(v)
}
return out
}
func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
out := make(map[string]interface{})
for k, v := range in {
out[fmt.Sprintf("%v", k)] = cleanUpMapValue(v)
}
return out
}
func cleanUpMapValue(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanUpInterfaceArray(v)
case map[interface{}]interface{}:
return cleanUpInterfaceMap(v)
case string:
return v
default:
return fmt.Sprintf("%v", v)
}
}
func main() {
s := make(map[string]interface{})
b := []byte(`---
aoeu:
- test
- aoeu
oaeu:
- { tase: aoeu, mahl: aoec}
`)
err := unmarshalYAML(b, &s)
if err != nil {
panic(err)
}
// s is still an empty map
fmt.Println(s) // map[]
}
The idea is to unmarshal YAML to map[string]interface{} (instead of map[interface{}]interface{}) is order to allow to serialize to JSON (where identifiers need to be strings). The unmarshalYAML function should provide the same func signture as yaml.Unmarshal...
Using Type assertion
Inside your unmarshalJSON() function the parameter s behaves like a local variable. When you assign something to it:
s = result
It will only change the value of the local variable.
Since you want it to work with changing the value of a *map[string]interface{} and that is what you pass to it, you could use a simple type assertion to obtain the map pointer from it, and pass this pointer to json.Unmarshal():
func unmarshalJSON(in []byte, s interface{}) error {
if m, ok := s.(*map[string]interface{}); !ok {
return errors.New("Expecting *map[string]interface{}")
} else {
return json.Unmarshal(in, m)
}
}
Try your modified, working example on the Go Playground.
Just passing it along
Also note that however this is completely unnecessary as json.Unmarshal() is also defined to take the destination as a value of type interface{}, the same thing you have. So you don't even have to do anything just pass it along:
func unmarshalJSON(in []byte, s interface{}) error {
return json.Unmarshal(in, s)
}
Try this on the Go Playground.
With a variable of function type
As an interesting thing note that the signature of your unmarshalJSON() and the library function json.Unmarshal() is identical:
// Yours:
func unmarshalJSON(in []byte, s interface{}) error
// json package
func Unmarshal(data []byte, v interface{}) error
This means there is another option, that is you could use a variable named unmarshalJSON of a function type, and just simply assign the function value json.Unmarshal:
var unmarshalJSON func([]byte, interface{}) error = json.Unmarshal
Now you have a variable unmarshalJSON which is of function type, and you can call it as if it would be a function:
err := unmarshalJSON(b, &s)
Try this function value on the Go Playground.
Now on to your unmarshalYAML() function
In your unmarshalYAML() you do the same mistake:
s = cleanUpInterfaceMap(result)
This will only change the value of your local s variable (parameter), and it will not "populate" the map (pointer) passed to unmarshalYAML().
Use the type assertion technique detailed above to obtain the pointer from the s interface{} argument, and once you have that, you can change the pointed object (the "outside" map).
func unmarshalYAML(in []byte, s interface{}) error {
var dest *map[string]interface{}
var ok bool
if dest, ok = s.(*map[string]interface{}); !ok {
return errors.New("Expecting *map[string]interface{}")
}
var result map[interface{}]interface{}
if err := yaml.Unmarshal(in, &result); err != nil {
return err
}
m := cleanUpInterfaceMap(result)
// m holds the results, dest is the pointer that was passed to us,
// we can just set the pointed object (map):
*dest = m
return nil
}
Related
I've got a method taking a target interface{} on a type that I use for database access like:
func (c *client) Query(query someType, target interface{}) error {
return c.db.Query(query).Decode(target)
}
This is then called like
result := resultType{}
if err := c.Query(myQuery, &result); err == nil {
// do sth with result
}
Which does what I want it do as I am passing the pointer address of result
The trouble I am now running into is that I do not know how I can mock this kind of behavior (mutating the passed reference) in a test.
In case I wouldn't need to pass interface{} I could imagine it being done like this:
type mockClient struct {
targetValue resultType
}
func (m *mockClient) Query(query someType, target *resultType) error {
*target = m.targetValue
return nil
}
If I try to do the same using my actual signature, I am not able to dereference the value contained in target like this:
type mockClient struct {
targetValue interface{}
}
func (m *mockClient) Query(query someType, target interface{}) error {
target = m.targetValue // this does not mutate the passed target
return nil
}
Can I dereference a pointer value when it is passed in as the empty interface? In case it is not possible, what would be another approach of testing the side effects my method has without having to resort to concrete types as arguments?
You can use 'reflect' package to do it.
package main
import (
"fmt"
"reflect"
)
type mockClient struct {}
func (m *mockClient) Query(query string, target interface{}) error {
a := "changed"
va := reflect.ValueOf(a)
reflect.ValueOf(target).Elem().Set(va)
return nil
}
func main() {
var mc mockClient
target := "initial"
mc.Query("qwe", &target)
fmt.Println(target)
}
The simple example to reference you can find here
A library foo exposes a type A and a function Fn in that library returns a *A.
I have defined a "wrapper" for A called B:
type B foo.A
Can I convert the *A to a *B without dereferencing the A?
In other words, if I have
a := foo.Fn() // a is a *A
b := B(*a)
return &b
How can I convert the *a to a *b without using *a?
The reason that I ask is that in the library that I am using, github.com/coreos/bbolt, the *DB value returned from the Open function includes a sync.Mutex and so the compiler complains when I try to make a copy of the Mutex.
UPDATE TO EXPLAIN HOW I'LL USE THIS
I have a
type Datastore struct {
*bolt.DB
}
I also have a function (one of many) like this:
func (ds *Datastore) ReadOne(bucket, id string, data interface{}) error {
return ds.View(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(bucket))
if err != nil {
return fmt.Errorf("opening bucket %s: %v", bucket, err)
}
bytes := b.Get([]byte(id))
if bytes == nil {
return fmt.Errorf("id %s not found", id)
}
if err := json.Unmarshal(bytes, data); err != nil {
return fmt.Errorf("unmarshalling item: %v", err)
}
return nil
})
}
I would like to mock the underlying BoltDB database using a hash map. I ran into a problem mocking this because of the View expecting a function that takes bolt.Tx. That tx is then used to create a new bucket in CreateBucketIfNotExists. I cannot replace that anonymous function argument with one that calls my hash map mock version of CreateBucketIfNotExists.
I came up with this:
package boltdb
import (
"github.com/coreos/bbolt"
)
type (
bucket bolt.Bucket
// Bucket is a wrapper for bolt.Bucket to facilitate mocking.
Bucket interface {
ForEach(fn func([]byte, []byte) error) error
Get(key []byte) []byte
NextSequence() (uint64, error)
Put(key, value []byte) error
}
db bolt.DB
// DB is a wrapper for bolt.DB to facilitate mocking.
DB interface {
Close() error
Update(fn func(*Tx) error) error
View(fn func(*Tx) error) error
}
transaction bolt.Tx
// Tx is a wrapper for bolt.Tx to facilitate mocking.
Tx interface {
CreateBucketIfNotExists(name []byte) (Bucket, error)
}
)
// ForEach executes a function for each key/value pair in a bucket.
func (b *bucket) ForEach(fn func([]byte, []byte) error) error {
return ((*bolt.Bucket)(b)).ForEach(fn)
}
// Get retrieves the value for a key in the bucket.
func (b *bucket) Get(key []byte) []byte {
return ((*bolt.Bucket)(b)).Get(key)
}
// NextSequence returns an autoincrementing integer for the bucket.
func (b *bucket) NextSequence() (uint64, error) {
return ((*bolt.Bucket)(b)).NextSequence()
}
// Put sets the value for a key in the bucket.
func (b *bucket) Put(key, value []byte) error {
return ((*bolt.Bucket)(b)).Put(key, value)
}
// Close releases all database resources.
func (db *db) Close() error {
return ((*bolt.DB)(db)).Close()
}
// Update executes a function within the context of a read-write managed transaction.
func (db *db) Update(fn func(Tx) error) error {
return ((*bolt.DB)(db)).Update(func(tx *bolt.Tx) error {
t := transaction(*tx)
return fn(&t)
})
}
// View executes a function within the context of a managed read-only transaction.
func (db *db) View(fn func(Tx) error) error {
return ((*bolt.DB)(db)).View(func(tx *bolt.Tx) error {
t := transaction(*tx)
return fn(&t)
})
}
// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
func (tx *transaction) CreateBucketIfNotExists(name []byte) (Bucket, error) {
b, err := ((*bolt.Tx)(tx)).CreateBucketIfNotExists(name)
if err != nil {
return nil, err
}
w := bucket(*b)
return &w, nil
}
So far, in my code, I am only using the functions shown above. I can add more if new code requires.
I will replace each bolt.DB with DB, bolt.Tx with Tx, and bolt.Bucket with Bucket in the real code. The mocker will use replacements for all three types that use the underlying hash map instead of storing to disk. I can then test all of my code, right down to the database calls.
You can simply / directly convert a value of type *A to a value of type *B, you just have to parenthesize *B:
a := foo.Fn() // a is a *A
b := (*B)(a)
return b
You can even convert the return value of the function call:
return (*B)(foo.Fn())
Try it on the Go Playground.
This is possible, because Spec: Conversions:
A non-constant value x can be converted to type T in any of these cases:
x is assignable to T.
...
And Spec: Assignability:
A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
...
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
Both *B and *A types are not defined, and the underlying type of *B is the same as the underlying type of *A (which is the pointer to the underlying type of whatever type there is in the type declaration of A).
I prefer not to dive into the rationale of the situation below. It has to do with unmarshaling an serialized object that can be any of a fixed set of types, but you don't know which type.
I have the following types:
type I interface {
Do()
}
type someI struct {}
func (i *someI) Do() {}
type otherI struct {}
func (i *otherI) Do() {}
So, two structs of which the pointers implement interface I.
Now I have this method that wants to return a value of type I:
func GetSomeI(marshalled []byte) (I, error) {
var obj interface{}
// The following method magically puts an instance
// of either someI or otherI into obj.
magicUnmarshall(marshalled, obj)
// The problem now is that we cannot return obj,
// because the raw structs don't implement I.
// One solution would be to do a type switch like this:
switch obj.(type) {
case someI:
i := obj.(someI)
return &i, nil
case otherI:
i := obj.(otherI)
return &i, nil
default:
return nil, errors.New("marschalled object was not of type I")
}
// But now consider the case that there are quite some
// different implementations of I.
// We would prefer to have a general way of getting
// a reference to obj.
}
To tell if a value wrapped in an interface{} implements some other interface (I), you may simply use a type assertion.
Note that you must pass the address of the variable you want results unmarshaled to.
For demonstration purposes, let's use the following magicUnmarshal() function:
func magicUnmarshal(what int, obj interface{}) {
v := reflect.ValueOf(obj).Elem()
switch what {
case 0:
v.Set(reflect.ValueOf(&someI{}))
case 1:
v.Set(reflect.ValueOf(&otherI{}))
case 2:
v.Set(reflect.ValueOf("just a string"))
case 3:
v.Set(reflect.ValueOf(someI{}))
case 4:
v.Set(reflect.ValueOf(otherI{}))
}
}
Note that case 3 and case 4 are returning non-pointers.
Your GetSomeI() implementation can be:
func GetSomeI(what int) (I, error) {
var obj interface{}
magicUnmarshal(what, &obj)
// Try the value as-is:
if i, ok := obj.(I); ok {
return i, nil
}
// No success. Try a pointer to the value:
v := reflect.Indirect(reflect.New(reflect.TypeOf(obj)))
v.Set(reflect.ValueOf(obj))
pobj := v.Addr().Interface()
if i, ok := pobj.(I); ok {
return i, nil
}
return nil, fmt.Errorf("%T does not implement I!", obj)
}
First GeSomeI() tests if the value got form magicUnmarshal() implements I, and if so, it is used as-is. If not, we construct a new using reflection, and get its address (a pointer to a value), and we test that. If that pointer implements I, we return it.
Testing it:
func main() {
for what := 0; what < 5; what++ {
i, err := GetSomeI(what)
fmt.Printf("%T %v\n", i, err)
}
}
And the output is (try it on the Go Playground):
*main.someI <nil>
*main.otherI <nil>
<nil> string does not implement I!
*main.someI <nil>
*main.otherI <nil>
I have a basic function in Go that opens a file and tries to decode its JSON contents.
I am trying to extract the default json.NewDecoder() function so I can easily mock this in my tests.
However, my implementation seems to return an error:
cannot use json.NewDecoder (type func(io.Reader) *json.Decoder) as type decoderFactory in argument to NewConfig
Code:
package main
import (
"encoding/json"
"fmt"
"io"
"os"
)
type openFile func(name string) (*os.File, error)
type decoderFactory func(r io.Reader) decoder
type decoder interface {
Decode(v interface{}) error
}
type Config struct {
ConsumerKey,
ConsumerSecret,
AccessToken,
AccessTokenSecret string
}
func NewConfig(open openFile, d decoderFactory) (*Config, error) {
c := new(Config)
file, err := open("some.file")
if err != nil {
return nil, fmt.Errorf("error opening config file")
}
defer file.Close()
decoder := d(file)
if err := decoder.Decode(&c); err != nil {
return nil, fmt.Errorf("error decoding config JSON")
}
return c, nil
}
func main() {
_, err := NewConfig(os.Open, json.NewDecoder)
if err != nil {
fmt.Fprintf(os.Stderr, "something bad happened: %v\n", err)
}
}
Here's a link to the Go playground
Where am I going wrong?
The json.NewDecoder() is a function with the following declaration:
func NewDecoder(r io.Reader) *Decoder
Its return type is *json.Decoder. json.Decoder is not an interface, it's a concrete type. And 2 function types are different if their return type is different: Spec: Function types:
A function type denotes the set of all functions with the same parameter and result types.
So you can't construct a new type returning an interface, and expect to be the same as json.NewDecoder, or that it'll accept the value json.NewDecoder.
But the "seemingly" easy fix is: define your decoderFactory to be a function type exactly what json.NewDecoder is:
type decoderFactory func(r io.Reader) *json.Decoder
This compiles, ok... but how to mock now?
How to mock now?
Of course in this form, you'll lose the possibility to mock json.NewDecoder() (because a "mocker" would have to return a value of type *json.Decoder and nothing else would be accepted). What to do then?
You have to use a different factory type. The factory type should be a function which returns an interface (of which you can provide different implementations), you were on the right track:
type MyDecoder interface {
Decode(v interface{}) error
// List other methods that you need from json.Decoder
}
type decoderFactory func(r io.Reader) MyDecoder
But you can't use json.NewEncoder as-is to pass as a value of decoderFactory. But fear not, it is very easy to create a function of type decoderFactory which will call json.NewEncoder() under the hood:
func jsonDecoderFact(r io.Reader) MyDecoder {
return json.NewDecoder(r)
}
We're mocking the behaviour of json.Decoder, and not the json.NewDecoder() factory function.
Using this jsonDecoderFact():
_, err := NewConfig(os.Open, jsonDecoderFact)
if err != nil {
fmt.Fprintf(os.Stderr, "something bad happened: %v\n", err)
}
This is valid and compiles, because jsonDecoderFact has exactly the same type as decoderFactory.
If you want to test / mock with a different implementation:
type TestDecoder struct {
r io.Reader
}
func (t TestDecoder) Decode(v interface{}) error {
// Test / mocking logic here
return nil
}
func testDecoderFact(r io.Reader) MyDecoder {
return TestDecoder{r}
}
Using it:
_, err2 := NewConfig(os.Open, testDecoderFact)
if err2 != nil {
fmt.Fprintf(os.Stderr, "something bad happened: %v\n", err2)
}
Try the examples on the Go Playground.
I want to invoke a function in Go, using reflect.Value.Call on a method value, and pass nil as a parameter. See the code below for an illustration.
I have tried using reflect.ValueOf(nil) and reflect.Value{} in the input array, but the first panics because nil has no value; the second panics when I pass it to Call, because it is a Zero reflect.Value.
Note that, as the code illustrates, it is certainly possible to pass nil to a function without reflection, including when that argument is the receiver. The question is: Is it possible to invoke a func using reflect.Value.Call, passing one of those parameters as nil?
You can build and run the code below at: http://play.golang.org/p/x9NXMDHWdM
package main
import "reflect"
type Thing struct{}
var (
thingPointer = &Thing{}
typ = reflect.TypeOf(thingPointer)
)
func (t *Thing) DoSomething() {
if t == nil {
println("t was nil")
} else {
println("t was not nil")
}
}
func normalInvokation() {
thingPointer.DoSomething()
// prints "t was not nil"
t := thingPointer
t = nil
t.DoSomething()
// prints "t was nil"
}
func reflectCallNonNil() {
m, _ := typ.MethodByName("DoSomething")
f := m.Func
f.Call([]reflect.Value{reflect.ValueOf(&Thing{})})
// prints "t was not nil"
}
func reflectCallNil() {
// m, _ := typ.MethodByName("DoSomething")
// f := m.Func
// f.Call(???)
// how can I use f.Call to print "t was nil" ?
}
func main() {
normalInvokation()
reflectCallNonNil()
reflectCallNil()
}
One option is to simply tell reflect that you mean a nil pointer to Thing:
func reflectCallNonNil() {
m, _ := typ.MethodByName("DoSomething")
f := m.Func
f.Call([]reflect.Value{reflect.ValueOf((*Thing)(nil))})
}
Also, you can use reflect.Zero which gives you a "zero value" for a type. So nil in this context is the zero value of pointer to Thing.
Thus, doing this will work:
func reflectCallNil() {
m, _ := typ.MethodByName("DoSomething")
f := m.Func
f.Call([]reflect.Value{reflect.Zero(reflect.TypeOf(&Thing{}))})
}