0

Can someone explain why the two aren't equivalent? The latter does build, but doesn't work as expected. I thought slices would be changed automatically, as contain a pointer to the array.

// Working spec

func TestProcessRecords(t *testing.T) {
    var messageSent []*sqs.SendMessageInput
    w := &SQSWriter{
        queueURL: aws.String("aQueueURL"),
        service: &mock.SQS{
            SendMessageStub: func(input *sqs.SendMessageInput) (*sqs.SendMessageOutput, error) {
                messageSent = append(messageSent, input)
                return nil, nil
            },
        },
    }
    inputEvent := readFirehoseEventFromFile(t, "../../../../testdata/firehose_event.json")
    processRecords(inputEvent.Records, w)
    assert.Equal(t, 2, len(inputEvent.Records))
    assert.Equal(t, 1, len(messageSent))
}

Attempted refactoring, as the mockedWriter will be used across specs

// Not Working spec

func mockWriter(messageSent []*sqs.SendMessageInput) *SQSWriter{
    return &SQSWriter{
        queueURL: aws.String("aQueueURL"),
        service: &mock.SQS{
            SendMessageStub: func(input *sqs.SendMessageInput) (*sqs.SendMessageOutput, error) {
                messageSent = append(messageSent, input)
                return nil, nil
            },
        },
    }
}

func TestProcessRecords(t *testing.T) {
    messageSent := []*sqs.SendMessageInput{}
    inputEvent := readFirehoseEventFromFile(t, "../../../../testdata/firehose_event.json")
    processRecords(inputEvent.Records, mockWriter(messageSent))
    assert.Equal(t, 2, len(inputEvent.Records))
    assert.Equal(t, 1, len(messageSent))
}

I should mention that I'm coming from a background in JS/Ruby/Python, and it is taking a bit of time to get a firmer grasp of go fundamentals.

Thanks in advance

Pratik Bothra
  • 2,642
  • 2
  • 30
  • 44
  • What exactly does "not working" mean? Remember that a slice contains a pointer to an array, but a) `append` returns a new slice which may point to a new array, and b) changes to the slice bounds won't be reflected in another copy of the slice – Adrian Apr 18 '18 at 20:14
  • 2
    True the slice contains a pointer to the array but also the len and cap, which are copied over when you pass it to a func and therefore they are not changed outside of the func. – mkopriva Apr 18 '18 at 20:14
  • slices are copied when passed to a function as a parameter, period. the fact that slice elements point to value doesn't change that fact. Either pass a pointer to struct containing the slice or pass a "pointer to slice". – mpm Apr 18 '18 at 20:14
  • 1
    Btw you should be able to fix your issue by passing a pointer to the slice to `mockWriter` and inside do `*messageSent = append(*messageSent, input)`. – mkopriva Apr 18 '18 at 20:18
  • @mkopriva That would explain it. I guess then I'm looking at something like this: https://stackoverflow.com/questions/20195296/golang-append-an-item-to-a-slice. Thanks! – Pratik Bothra Apr 18 '18 at 20:20

1 Answers1

1

This was the answer, all credits to @mkopriva.

func mockWriter(messageSent *[]*sqs.SendMessageInput) *SQSWriter{
    return &SQSWriter{
        queueURL: aws.String("aQueueURL"),
        service: &mock.SQS{
            SendMessageStub: func(input *sqs.SendMessageInput) (*sqs.SendMessageOutput, error) {
                *messageSent = *append(messageSent, input)
                return nil, nil
            },
        },
    }
}

func TestProcessRecords(t *testing.T) {
    messageSent := []*sqs.SendMessageInput{}
    inputEvent := readFirehoseEventFromFile(t, "../../../../testdata/firehose_event.json")
    processRecords(inputEvent.Records, mockWriter(&messageSent))
    assert.Equal(t, 2, len(inputEvent.Records))
    assert.Equal(t, 1, len(messageSent))
}
mkopriva
  • 35,176
  • 4
  • 57
  • 71
Pratik Bothra
  • 2,642
  • 2
  • 30
  • 44
  • 1
    Remember that all function parameters are passed by value. And that appending to a slice returns a new slice. So you have to use a pointer this way so that the caller gets the new slice. – Michael Hampton Apr 18 '18 at 21:41
  • Havent tried it but i believe that it should be ```*messageSent = append(*messageSent, input)``` instead of ```*messageSent = *append(messageSent, input)``` – Martin Spasov Apr 18 '18 at 22:59