golang if initialization statement scoped to inner if block. Why? [duplicate] - if-statement

This question already has answers here:
Golang mixed assignment and declaration
(4 answers)
Closed 4 years ago.
I've found a bug in my code
func receive() (err error) {
if v, err := produce(); err == nil {
fmt.Println("value: ", v)
}
return
}
Error is never returning from this function, but I was absolutely sure it should.
After some testing I understood that err is redeclared in the if statement. More than that - all variables are always redeclared in short variable assignment inside if statement, despite they were declared before.
This is working code
func receive() (err error) {
v, err := produce()
if err == nil {
fmt.Println("value: ", v)
}
return
}
Here is an example: https://play.golang.org/p/1AWBsPbLiI1
Seems like if statement
//some code
if <init_statement>; <expression> {}
//more code
is equivalent to
//some code
{
<init_statement>
if expression {}
}
//more code
So, my questions:
1) why existing variables are not used
2) why such scoping is not mentioned in documentation/language spec
3) why compiler doesn't say that no one returns a value

1) Because the language spec says so.
2) It is:
Each "if", "for", and "switch" statement is considered to be in its own implicit block"
3) You did return at the end of your function. Do not use named return values.

A compiler may disallow an empty expression list in a "return"
statement if a different entity (constant, type, or variable) with the
same name as a result parameter is in scope at the place of the
return.
Try to return the value inside if scope and you will get to know that the err variable is shadowed inside the if scope.
func receive1() (err error) {
if v, err := produce(); err != nil {
fmt.Println("value2: ", v)
return // err is shadowed during return
}
return
}
Above code will show an error as:
err is shadowed during return
Playground example
while in the second function the err declared in the return statement is assigned with local variable scope:
// err is the return value. It's OK
func receive2() (err error) {
v, err := produce()
if err != nil {
fmt.Println("value2: ", v)
return
}
return
}
Try it on playground
The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
func complexF3() (re float64, im float64) {
re = 7.0
im = 4.0
return
}
Regardless of how they are declared, all the result values are
initialized to the zero values for their type upon entry to the
function. A "return" statement that specifies results sets the result
parameters before any deferred functions are executed.

Related

Go testify package: segfault when trying to avoid ambiguous call

I am writing the following unit test:
type mockQux struct {
mock.Mock
MockInterface
calculateHash func(ctx context.Context, foo *entities.Foo, bar model.Bar, baz *model.Baz) (uint64, error)
}
type MockInterface interface {
On(methodName string, arguments ...interface{}) *mock.Call
AssertExpectations func(t mock.TestingT)
}
func (m *mockQux) TestCalculateHash(t *testing.T) {
mq := new(mockQux)
ctx := context.Background()
foo := &entities.Foo{
// foo's fields
}
// create instances of model.Bar and &model.Baz the same way I created foo variable
mq.On("calculateHash", ctx, foo, bar, baz).Return(uint64(123), nil)
hash, err := m.Mock.calculateHash(ctx, foo, bar, baz)
assert.Equal(t, uint64(123), hash)
assert.Nil(t, err)
m.Mock.AssertExpectations(t)
}
func TestCalculateHash(t *testing.T) {
m := new(mockQux)
m.TestCalculateHash(t)
}
Running go test and go test -c, why do I get a segfault on On and AssertExpectations?
I've tried debugging this with delve, but it crashes whenever I run it, even if I instruct it to step over the problematic lines. I guess the problem might be that I improperly reference the variables in arguments to mq.On or that I don't initialize all the fields (these structs are pretty complex).
There are too many fail point in your code sample to tell what's the exact root cause of the segfault. That's generally not how testify mock are used. You don't need either your MockInterface definition. Also you cannot have a segfault on 2 different locations, your program either segfault on On or AssertExpectations. That cannot be both. I strongly suspect though that your segfault come from this call:
hash, err := m.Mock.calculateHash(ctx, foo, bar, baz)
as this function pointer from your struct does not seem to be initialized.
About how to use mock in testify, we usually do something like that.
Here is a minimal nominal code without any business logic:
type ConcreteType struct {}
func (m *ConcreteType) DoSomething() int { return 3 }
type DoSomethinger interface {
DoSomething() int
}
func UseConcreteType(s DoSomethinger) error {
if val := s.DoSomething(); val != 3 {
return fmt.Errorf("unexpected value: %d", val)
}
}
In your test you would do something like that:
type DoSomethingMock struct {
mock.Mock
}
func (m *DoSomethingMock) DoSomething() int {
args := m.Called()
return args.Int(0)
}
func TestUseConcrete(t *testing.T) {
m := &DoSomethingMock{}
m.On("DoSomething").Return(4)
err := UseConcreteType(m)
require.Error(t, err)
}

Mocking a inner function(or even more deep) for testing in go

is there a way to achieve this? I want to Mock the response of a function call from within another function call. Example
main.go
type Crs struct {}
func (cr crs)TheFunction() error {
// Some code
_ := ToMockResponse(hello string)
return nil
}
func ToMockResponse() error {
return somerror
}
and in my test file
main_test.go
func TestTheFunction(t *testing.T) {
cr = Crs{}
mockInstance = new(randomMock)
mockInstance.On("ToMockResponse").Return(nil)
err := cr.TheFunction()
assert.NoError(t, err)
}
I'm not sure if what I did is correct. What I'm trying to achieve is that I just want to have a Mock response of ToMockResponse whenever it's being called inside TheFunction
I have seen and read most of the tutorial but all of them shows a Mock response from a method of a class. But there are no function-to-function mocking samples. Hope you can provide a solution to this.
Without getting into whether you should do this, and assuming that you have a valid reason to do so, one way to mock functions is to use them via a level of indirection. You can then substitute a suitable alternative in your indirection for the purposes of testing.
An interface is one way to achieve that, but GoLang supports functions as values, so another way is to use a simple variable of an appropriate function type:
Adapted to your example, this might look similar to:
var toMockResponse = ToMockResponse
func (cr crs)TheFunction() error {
// Some code
_ := toMockResponse(hello string)
return nil
}
func ToMockResponse() error {
return somerror
}
and your test:
func TestTheFunction(t *testing.T) {
cr = Crs{}
ofn := toMockResponse
toMockResponse = func(string) error { return nil }
defer func() { toMockResponse = ofn }()
err := cr.TheFunction()
assert.NoError(t, err)
}
I have assumed that you need to export the ToMockResponse; the function variable is deliberately not exported so that it cannot be manipulated outside of the package itself.
If the function being redirected is itself not exported, denying the ability to use the case difference of exported vs non-exported symbols to differentiate them, then you may need to be a bit more creative with your naming. e.g. a variable called toMockResponseFn.
Footnote
ofn is mnemonic for "original function". In a more complicated test you can preserve the pattern by creating a scope for each ofn you need (defer operates w.r.t the containing function, not the scope):
{
ofn := toMockResponse
toMockResponse = func(string) error { return nil }
defer func() { toMockResponse = ofn }()
}
{
ofn := now
now = func() time.Time { return time.Date(..etc..) }
defer func() { now = ofn }()
}

Golang Unit Testing: error conditions

How do I test error conditions, & other unexpected code flow, in Golang?
Suppose I have code as follows:
import crypto
func A(args) error {
x, err := crypto.B()
if err != nil {
return err
}
return nil
}
B is some function. I believe that the only way for me to test this failure scenario is to change the value of B for my test (mock it so it returns an error). Things I have tried:
1) monkeypatch the function just before the test and unpatch afterwards.
This was a horrible idea. Caused all sorts of weird issues as the
tests were running.
2) Pass B as an argument to A. This is all well and good but it also
means that I have to change the definition for A and then update
every use of it every time the implementation changes. Furthermore,
A may be using many imported functions and putting them all in the
type definition for A just seems ugly and not idiomatic.
3) Change the value of B for my test, then change it back.
import crypto.B
cryptoB = crypto.B
func A(args) error {
x, err := cryptoB()
if err != nil {
return err
}
...
}
func Test_A(t *testing.T) {
oldB := cryptoB
cryptoB = mockB
// run test
cryptoB = oldB
...
}
I've been using method #3 as it allows me fine grained unit testing control while not creating too much overhead. That said, it's ugly and causes confusion e.g. "Why are we renaming all of the imported functions?".
What should I be doing? Please help me so my codes can be more better :)
Like you, I've never seen a solution to this problem that's totally satisfied me.
In regards to your example 3, remember that you can defer the reset of the cryptoB. This, combined with good naming of the mock functions, would make it clear what you are trying to accomplish. There are obviously still code-style issues with this approach, with having all of your references listed line by line, twice, at the start of your file.
func TestSomething(t *testing.T) {
cryptoB = mockedFunc
defer func() {
cryptoB = crypto.B
}
// Testing goes on here
}
Option 4
The other approach (which I would favor) would be to turn the functions you export into methods of a CryptoA struct. The struct would store whatever dependencies and state it requires. Something like this:
type CryptoA struct {
cryptoB func() error
}
func (a *CryptoA) CryptoA() error {
return a.cryptoB()
}
func NewCryptoA() *CryptoA {
return &CryptoA{
cryptoB: func() error {
return nil
},
}
}
and mocking would be very similar:
func TestSomething(t *testing.T) {
a := NewCryptoA()
a.cryptoB = mockedFunc
// Testing goes on here
}
With this approach you lose some by your API having an extra step for invocation, a := NewCryptoA(), and you still have to name all of your dependencies, but you make gains by having the state of your API specific to each client.
Maybe there is a flaw in your API, and you leak data somewhere unexpected, or there is some state modifications that you don't expect. If you create a new CryptoA for each caller, then maybe the amount of data you leak, or the number of clients with a corrupted state, is limited, and therefore the impact less severe/abusable. I'm obviously spitballing at how this applies to your codebase, but hopefully you can get the idea of how this is a win.
Also, if you want to give the ability for users to specify their own hash algorithm, you can swap it out internally, and since it's private you maintain confidence that the function is up to the standards of your API. Again, I'm obviously spitballing.
I'll be skimming the answers to see if there's an idiomatic way to do this that I'm unaware of.
My preferred approach is usually to make A a method, and store the dependencies in the receiver object. Example:
import crypto;
type CryptoIface interface {
B() (string, error)
}
type standardCrypto struct {}
var _ CryptoIface = &standardCrypto{}
func (c *standardCrypto) B() (string, error) {
return crypto.B()
}
func main() {
crypto = &standardCrypto{}
err = A(crypto, ...)
// stuff
}
func A(crypto CryptoIface, args ...string) error {
result, err := crypto.B()
if err != nil {
return err
}
// do something with result
return nil
}
Then for your tests, you can easily create a mock version of the CryptoIface:
type mockCrypto struct {
Bfunc func(args ...string) error
}
func (c *mockCrypto) B(args ...string) error {
return c.Bfunc(args...)
}
func TestA(t *testing.T) {
c := &mockCrypto{
Bfunc: func(_ ...string) error {
return errors.New("test error")
}
}
err := A(c)
if err.String() != "test error" {
t.Errorf("Unexpected error: %s", err)
}
}
This approach is usually most useful for large projects or APIs where it makes sense to include a number of methods on a single object. Use your discretion. For smaller cases, this will be overkill.

Golang templates (and passing funcs to template)

I'm getting an error when I try and access a function I'm passing to my template:
Error: template: struct.tpl:3: function "makeGoName" not defined
Can anyone please let me know what I'm doing wrong?
Template file (struct.tpl):
type {{.data.tableName}} struct {
{{range $key, $value := .data.tableData}}
{{makeGoName $value.colName}} {{$value.colType}} `db:"{{makeDBName $value.dbColName}},json:"{{$value.dbColName}}"`
{{end}}
}
Calling file:
type tplData struct {
tableName string
tableData interface{}
}
func doStuff() {
t, err := template.ParseFiles("templates/struct.tpl")
if err != nil {
errorQuit(err)
}
t = t.Funcs(template.FuncMap{
"makeGoName": makeGoName,
"makeDBName": makeDBName,
})
data := tplData{
tableName: tableName,
tableData: tableInfo,
}
t.Execute(os.Stdout, data)
}
func makeGoName(name string) string {
return name
}
func makeDBName(name string) string {
return name
}
This is for a program that generates struct boilerplate code (in case anyone is wondering why I'm doing that in my template).
Custom functions need to be registered before parsing the templates, else the parser would not be able to tell whether an identifier is a valid function name or not. Templates are designed to be statically analyzable, and this is a requirement to that.
You can first create a new, undefined template with template.New(), and besides the template.ParseFiles() function, the template.Template type (returned by New()) also has a Template.ParseFiles() method, you can call that.
Something like this:
t, err := template.New("").Funcs(template.FuncMap{
"makeGoName": makeGoName,
"makeDBName": makeDBName,
}).ParseFiles("templates/struct.tpl")
Note that the template.ParseFiles() function also calls template.New() under the hood, passing the name of the first file as the template name.
Also Template.Execute() returns an error, print that to see if no output is generated, e.g.:
if err := t.Execute(os.Stdout, data); err != nil {
fmt.Println(err)
}
When registering custom functions for your template and using ParseFiles() you need to specify the name of the template when instantiating it and executing it. You also need to call ParseFiles() after you call Funcs().
// Create a named template with custom functions
t, err := template.New("struct.tpl").Funcs(template.FuncMap{
"makeGoName": makeGoName,
"makeDBName": makeDBName,
}).ParseFiles("templates/struct.tpl") // Parse the template file
if err != nil {
errorQuit(err)
}
// Execute the named template
err = t.ExecuteTemplate(os.Stdout, "struct.tpl", data)
if err != nil {
errorQuit(err)
}
When working with named templates the name is the filename without the directory path e.g. struct.tpl not templates/struct.tpl. So the name in New() and ExecuteTemplate() should be the string struct.tpl.

Golang casting a multiple return value to match named result parameter

Let's assume I want to define a function with named result parameters, one of which is a string. This function internally calls another function, that returns a bytes representation of such string.
Is there a way to cast the result without using a temporary variable?
func main() {
out, _ := bar("Example")
fmt.Println(out)
}
func foo(s string) ([]byte, error) {
return []byte(s), nil
}
func bar(in string) (out string, err error) {
// is there a way to assign the result to out
// casting the value to string in the same line
// istead of using the tmp variable?
tmp, err := foo(in)
if err != nil {
return "", err
}
return string(tmp), nil
}
The idea is that, if that's possible, I could potentially shorten the code to
func bar(in string) (out string, err error) {
// assuming there is a way to cast out to string
out, err := foo(in)
return
}
Does it make sense?
There is no way to cast in a multiple return from a function. That doesn't mean you can't shorten your code though. http://play.golang.org/p/bf4D71_rZF If you don't care about the error then just cast the variable in your inline return
1 line of code won't make a huge difference but having a tmp variable actually sticking around for the entire function is a problem. Temporary variables should be temporary, obviously. For that, you can declare tmp in a new scope.
var s string;
{
tmp, err := foo(in)
s = string(tmp)
}
//tmp no longer exists here.
//Other code is not disturbed by a useless tmp variable.
I may be just being stupid here as I am new to Go, I learnt this trick from C, turns out it works for Go as well.