onsi / gomega

Ginkgo's Preferred Matcher Library
http://onsi.github.io/gomega/
MIT License
2.15k stars 282 forks source link

HaveField: cannot call method with pointer receiver for values #696

Open pohly opened 11 months ago

pohly commented 11 months ago

I recently suggested replacing these checks with ConsistOf + HaveField("GetName()", Equal:

    gomega.Expect(len(list.Items)).To(gomega.BeIdenticalTo(2))
    framework.ExpectEqual((list.Items[0].GetName() == name1 && list.Items[1].GetName() == name2) ||
        (list.Items[0].GetName() == name2 && list.Items[1].GetName() == name1), true)

=>

gomega.Expect(list.Items).To(gomega.ConsistOf(gomega.HaveField("GetName()", gomega.Equal(name1)), gomega.HaveField("GetName()", gomega.Equal(name2))))

That didn't work. It turned out that the slice elements are values and their GetName method is only defined for pointers. Go can call it anyway, but Gomega can't (or doesn't). Perhaps it should also support that?

Here's a reproducer:

package gomegatest

import (
    "testing"

    "github.com/onsi/gomega"
)

type pointerobject struct {
    name string
}

func (p *pointerobject) GetName() string {
    return p.name
}

type valueobject struct {
    name string
}

func (v valueobject) GetName() string {
    return v.name
}

type object interface {
    GetName() string
}

var _ object = valueobject{}

// Only pointer implements object interface, not value.
var _ object = &pointerobject{}

// var _ object = pointerobject{}

func TestConsistsOf(t *testing.T) {
    g := gomega.NewGomegaWithT(t)
    e := gomega.ConsistOf(gomega.HaveField("GetName()", gomega.Equal("A")), gomega.HaveField("GetName()", gomega.Equal("B")))

    g.Expect([]valueobject{{"A"}, {"B"}}).To(e)   // works
    g.Expect([]pointerobject{{"A"}, {"B"}}).To(e) // fails
}