Decorations are not applied to parameters passed to group constructors
Describe the bug If I have a struct being injected as part of a group, and that struct contains an interface type with decorations, then the decorations for the interface type are ignored for the group constructor.
For example, suppose we have an interface Animal that has a production implementation of ProdBear, and a unit test decoration that returns MockBunny. When groups are not utilized, my app always populates bunny, since it applies the bunny decorator. However, when I create a Zoo with a group of exhibits, then bear is populated for the Zoo exhibits -- everywhere else bunny is populated.
To Reproduce
package main_test
import (
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/fx"
"go.uber.org/fx/fxtest"
)
type Animal interface {
Name() string
}
type ProdBear struct {
}
var _ Animal = (*ProdBear)(nil)
func NewProdBear() *ProdBear {
return &ProdBear{}
}
func (p *ProdBear) Name() string {
return "bear"
}
type MockBunny struct {
}
var _ Animal = (*MockBunny)(nil)
func (r *MockBunny) Name() string {
return "bunny"
}
func NewMockBunny() *MockBunny {
return &MockBunny{}
}
type Exhibit struct {
Animal Animal
}
func NewExhibit(a Animal) *Exhibit {
return &Exhibit{Animal: a}
}
type ZooParams struct {
fx.In
Exhibits []*Exhibit `group:"exhibits"`
}
type Zoo struct {
Exhibits []*Exhibit
}
func NewZoo(p ZooParams) *Zoo {
return &Zoo{Exhibits: p.Exhibits}
}
type Trainer struct {
Animal Animal
}
func NewTrainer(a Animal) *Trainer {
return &Trainer{Animal: a}
}
func TestFxApp(t *testing.T) {
var env struct {
fx.In
Animal Animal
Trainer *Trainer
Zoo *Zoo
}
app := fxtest.New(t,
fx.Provide(
fx.Annotate(NewProdBear, fx.As(new(Animal))),
),
fx.Decorate(
fx.Annotate(NewMockBunny, fx.As(new(Animal))),
),
fx.Provide(
// Using `group` here results in NewExhibit() being passed a bear instead of a bunny.
fx.Annotate(NewExhibit, fx.ResultTags(`group:"exhibits"`)),
),
fx.Provide(NewTrainer),
fx.Provide(NewZoo),
fx.Populate(&env),
)
defer app.RequireStart().RequireStop()
assert.Equal(t, "bunny", env.Animal.Name())
assert.Equal(t, "bunny", env.Trainer.Animal.Name())
// This fails! Zoo contains a group of exhibits, and the NewExhibit()
// constructor is only given the prod value, not the decorated value.
// expected: "bunny"
// actual : "bear"
assert.Equal(t, "bunny", env.Zoo.Exhibits[0].Animal.Name())
}
Expected behavior I would expect the above unit test to pass.
Additional context
Tested with fx v1.17.1 and dig v1.14.1