@@ -3681,3 +3681,178 @@ func uintPtr(v uint) *uint { return &v }
36813681func boolPtr (v bool ) * bool { return & v }
36823682func floatPtr (v float64 ) * float64 { return & v }
36833683func interfacePtr (v any ) * any { return & v }
3684+
3685+ type TestMapFieldName struct {
3686+ HostName string
3687+ Username string
3688+ }
3689+
3690+ func TestDecoder_MapFieldNameMapFromStruct (t * testing.T ) {
3691+ t .Parallel ()
3692+
3693+ var structKeys map [string ]any
3694+
3695+ decoder , err := NewDecoder (& DecoderConfig {
3696+ ErrorUnused : true , // Enable error on unused keys
3697+ Result : & structKeys ,
3698+ MapFieldName : func (s string ) string {
3699+ if s == "HostName" {
3700+ return "host_name"
3701+ }
3702+ return s
3703+ },
3704+ })
3705+ if err != nil {
3706+ t .Fatalf ("err: %s" , err )
3707+ }
3708+
3709+ var input TestMapFieldName
3710+
3711+ err = decoder .Decode (& input )
3712+ if err != nil {
3713+ t .Fatalf ("err: %s" , err )
3714+ }
3715+
3716+ _ , ok := structKeys ["host_name" ]
3717+ if ! ok {
3718+ t .Fatal ("expected host_name to exist" )
3719+ }
3720+
3721+ _ , ok = structKeys ["Username" ]
3722+ if ! ok {
3723+ t .Fatal ("expected Username to exist" )
3724+ }
3725+ }
3726+
3727+ func TestDecoder_MapFieldNameStructFromMap (t * testing.T ) {
3728+ t .Parallel ()
3729+
3730+ foo := TestMapFieldName {}
3731+
3732+ decoder , err := NewDecoder (& DecoderConfig {
3733+ Result : & foo ,
3734+ MapFieldName : func (s string ) string {
3735+ if s == "HostName" {
3736+ return "host_name"
3737+ }
3738+ if s == "Username" {
3739+ return "user_name"
3740+ }
3741+ return s
3742+ },
3743+ })
3744+ if err != nil {
3745+ t .Fatalf ("err: %s" , err )
3746+ }
3747+
3748+ structKeys := map [string ]any {
3749+ "host_name" : "foo" ,
3750+ "user_name" : "bar" ,
3751+ }
3752+
3753+ err = decoder .Decode (& structKeys )
3754+ if err != nil {
3755+ t .Fatalf ("err: %s" , err )
3756+ }
3757+
3758+ if foo .HostName != "foo" {
3759+ t .Fatal ("expected HostName to be foo" )
3760+ }
3761+
3762+ if foo .Username != "bar" {
3763+ t .Fatal ("expected Username to be bar" )
3764+ }
3765+ }
3766+
3767+ func TestDecoder_MapFieldNameWithMatchName (t * testing.T ) {
3768+ t .Parallel ()
3769+
3770+ type Target struct {
3771+ HostName string
3772+ Username string
3773+ }
3774+
3775+ input := map [string ]any {
3776+ "HOST_NAME" : "server1" ,
3777+ "user_name" : "admin" ,
3778+ }
3779+
3780+ var result Target
3781+ decoder , err := NewDecoder (& DecoderConfig {
3782+ Result : & result ,
3783+ MapFieldName : func (s string ) string {
3784+ // Convert HostName -> host_name, Username -> user_name
3785+ if s == "HostName" {
3786+ return "host_name"
3787+ }
3788+ if s == "Username" {
3789+ return "user_name"
3790+ }
3791+ return s
3792+ },
3793+ MatchName : strings .EqualFold , // Case-insensitive fallback
3794+ })
3795+ if err != nil {
3796+ t .Fatalf ("err: %s" , err )
3797+ }
3798+
3799+ err = decoder .Decode (input )
3800+ if err != nil {
3801+ t .Fatalf ("err: %s" , err )
3802+ }
3803+
3804+ // HOST_NAME should match host_name via case-insensitive MatchName
3805+ if result .HostName != "server1" {
3806+ t .Fatalf ("expected HostName to be 'server1', got '%s'" , result .HostName )
3807+ }
3808+
3809+ // user_name matches exactly
3810+ if result .Username != "admin" {
3811+ t .Fatalf ("expected Username to be 'admin', got '%s'" , result .Username )
3812+ }
3813+ }
3814+
3815+ func TestDecoder_MapFieldNameWithIgnoreUntaggedFields (t * testing.T ) {
3816+ t .Parallel ()
3817+
3818+ type Target struct {
3819+ TaggedField string `mapstructure:"tagged_field"`
3820+ UntaggedField string
3821+ }
3822+
3823+ input := map [string ]any {
3824+ "tagged_field" : "tagged_value" ,
3825+ "untagged_field" : "untagged_value" ,
3826+ }
3827+
3828+ var result Target
3829+ decoder , err := NewDecoder (& DecoderConfig {
3830+ Result : & result ,
3831+ IgnoreUntaggedFields : true ,
3832+ MapFieldName : func (s string ) string {
3833+ // This would convert UntaggedField -> untagged_field,
3834+ // but IgnoreUntaggedFields takes precedence
3835+ if s == "UntaggedField" {
3836+ return "untagged_field"
3837+ }
3838+ return s
3839+ },
3840+ })
3841+ if err != nil {
3842+ t .Fatalf ("err: %s" , err )
3843+ }
3844+
3845+ err = decoder .Decode (input )
3846+ if err != nil {
3847+ t .Fatalf ("err: %s" , err )
3848+ }
3849+
3850+ if result .TaggedField != "tagged_value" {
3851+ t .Fatalf ("expected TaggedField to be 'tagged_value', got '%s'" , result .TaggedField )
3852+ }
3853+
3854+ // UntaggedField should remain empty because IgnoreUntaggedFields is true
3855+ if result .UntaggedField != "" {
3856+ t .Fatalf ("expected UntaggedField to be empty due to IgnoreUntaggedFields, got '%s'" , result .UntaggedField )
3857+ }
3858+ }
0 commit comments