Skip to content

Commit

Permalink
Fix a number of issues with template-data merging
Browse files Browse the repository at this point in the history
In #883 it was noted there were issues with merging template-data config. In the span of investigaiton,
a number of other bugs were discovered with config merging in general. This commit addresses those issues and
adds configuration in `.mockery_moq.yml` to prove it was fixed.
  • Loading branch information
LandonTClipp committed Jan 6, 2025
1 parent 95cf7ed commit 237c4fa
Show file tree
Hide file tree
Showing 8 changed files with 1,410 additions and 221 deletions.
13 changes: 12 additions & 1 deletion .mockery_moq.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,20 @@ boilerplate-file: "./.boilerplate.txt"
mockname: "Moq{{.InterfaceName}}"
filename: "mocks_moq_test.go"
all: true
template-data:
skip-ensure: False
stub-impl: True
with-resets: True
packages:
github.com/vektra/mockery/v3/internal/fixtures:
config:
all: false
include-regex: '.*'
exclude-regex: 'RequesterGenerics'
exclude-regex: 'RequesterGenerics'
interfaces:
Requester:
configs:
- mockname: "Moq{{.InterfaceName}}SkipEnsure"
template-data:
skip-ensure: True
- {}
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ tasks:
mocks.generate.moq:
silent: True
cmds:
- MOCKERY_CONFIG=./.mockery_moq.yaml go run .
- MOCKERY_CONFIG=./.mockery_moq.yml go run .

mocks.generate:
desc: generate mocks
Expand Down
5 changes: 1 addition & 4 deletions internal/cmd/mockery.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ func (r *RootApp) Run() error {
ifaceLog.Debug().Msg("interfaces is nil")
}
ifaceConfig := pkgConfig.GetInterfaceConfig(ctx, iface.Name)
ifaceLog.Debug().Int("len", len(ifaceConfig.Configs)).Str("fmt", fmt.Sprintf("%#v", ifaceConfig)).Msg("interface configs length")
for _, ifaceConfig := range ifaceConfig.Configs {
if err := ifaceConfig.ParseTemplates(ifaceCtx, iface, iface.Pkg); err != nil {
log.Err(err).Msg("Can't parse config templates for interface")
Expand Down Expand Up @@ -278,15 +277,13 @@ func (r *RootApp) Run() error {
if err != nil {
return err
}
fileLog.Debug().Str("mock-name", *packageConfig.Config.MockName).Msg("package config mockname before parsing")
if err := packageConfig.Config.ParseTemplates(ctx, nil, interfacesInFile.srcPkg); err != nil {
return err
}
fileLog.Debug().Str("mock-name", *packageConfig.Config.MockName).Msg("package config mockname after parsing")

generator, err := pkg.NewTemplateGenerator(
fileCtx,
interfacesInFile.interfaces[0].Pkg,
interfacesInFile.srcPkg,
interfacesInFile.outFilePath.Parent(),
*packageConfig.Config.Template,
pkg.Formatter(*r.Config.Formatter),
Expand Down
59 changes: 47 additions & 12 deletions internal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,28 +132,63 @@ func (c *RootConfig) ConfigFileUsed() *pathlib.Path {
return c.configFile
}

// mergreStringMaps merges two (possibly nested) maps.
func mergeStringMaps(src, dest map[string]any) {
for srcKey, srcValue := range src {
if destValue, exists := dest[srcKey]; exists {
// If the source value is a map, merge recursively
if destMap, ok := destValue.(map[string]any); ok {
if srcMap, ok := srcValue.(map[string]any); ok {
mergeStringMaps(srcMap, destMap)
continue
}
}
continue
}
// Otherwise, set the value directly
dest[srcKey] = srcValue
}
}

// mergeConfigs merges the values from c1 into c2.
func mergeConfigs(ctx context.Context, c1 Config, c2 *Config) {
func mergeConfigs(ctx context.Context, src Config, dest *Config) {
log := zerolog.Ctx(ctx)
// Merge root config with package config
c1Value := reflect.ValueOf(c1)
c2Value := reflect.ValueOf(c2)
srcValue := reflect.ValueOf(src)
destValue := reflect.ValueOf(dest)

for i := 0; i < c1Value.NumField(); i++ {
for i := 0; i < srcValue.NumField(); i++ {
fieldLog := log.With().
Int("index", i).
Str("name", c1Value.Type().Field(i).Name).
Str("name", srcValue.Type().Field(i).Name).
Logger()
fieldLog.Debug().Msg("Iterating over field for merging")
c1FieldValue := c1Value.Field(i)
c2FieldValue := c2Value.Elem().Field(i)

if c2FieldValue.CanSet() && c2FieldValue.IsZero() {
c2FieldValue.Set(c1FieldValue)
srcFieldValue := srcValue.Field(i)
destFieldValue := destValue.Elem().Field(i)

if srcFieldValue.Kind() == reflect.Map {
srcMap := srcFieldValue.Interface().(map[string]any)
destMap := destFieldValue.Interface().(map[string]any)
if destMap == nil {
destFieldValue.Set(reflect.ValueOf(make(map[string]any)))
}
destMap = destFieldValue.Interface().(map[string]any)
mergeStringMaps(srcMap, destMap)
} else if srcFieldValue.Kind() == reflect.Pointer && destFieldValue.IsNil() {
// Attribute is a pointer. We need to allocate a new value of the
// same type as the type being pointed to.
newValue := reflect.New(srcFieldValue.Elem().Type())
// Then, set this new value to the same value as the src.
newValue.Elem().Set(srcFieldValue.Elem())
// newValue is already an address, so we can set destFieldValue
// to it as-is.
destFieldValue.Set(newValue)
} else if destFieldValue.CanSet() && destFieldValue.IsZero() {
destFieldValue.Set(srcFieldValue)
} else {
fieldLog.Debug().
Bool("can-set", c2FieldValue.CanSet()).
Bool("is-zero", c2FieldValue.IsZero()).
Bool("can-set", destFieldValue.CanSet()).
Bool("is-zero", destFieldValue.IsZero()).
Msg("field not addressable, not merging.")
}
}
Expand Down
Loading

0 comments on commit 237c4fa

Please sign in to comment.