Skip to content

Commit

Permalink
Enable skipping unexported fields
Browse files Browse the repository at this point in the history
Co-Authored-By: Tom Patterer <[email protected]>
  • Loading branch information
relistan and patoms committed Nov 20, 2024
1 parent 5d2ad4e commit c08cbc3
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
7 changes: 6 additions & 1 deletion copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ type Option struct {
// Custom field name mappings to copy values with different names in `fromValue` and `toValue` types.
// Examples can be found in `copier_field_name_mapping_test.go`.
FieldNameMapping []FieldNameMapping

// SkipUnexported will skip private fields: they will not be copied
SkipUnexported bool
}

func (opt Option) converters() map[converterPair]TypeConverter {
Expand Down Expand Up @@ -320,7 +323,9 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)

// check source
if source.IsValid() {
copyUnexportedStructFields(dest, source)
if !opt.SkipUnexported {
copyUnexportedStructFields(dest, source)
}

// Copy from source field to dest field or method
fromTypeFields := deepFields(fromType)
Expand Down
50 changes: 50 additions & 0 deletions copier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ func TestStructField(t *testing.T) {
DeepCopy: true,
}

optionsSkipUnexported := copier.Option{
SkipUnexported: true,
}

checkDetail := func(t *testing.T, source Detail, target Detail) {
if source.Info1 != target.Info1 {
t.Errorf("info1 is diff: source: %v, target: %v", source.Info1, target.Info1)
Expand Down Expand Up @@ -704,6 +708,52 @@ func TestStructField(t *testing.T) {
}
})
})

t.Run("should handle unexported fields", func(t *testing.T) {
t.Run("should copy unexported fields", func(t *testing.T) {
from := &struct {
unexportedField string
}{
unexportedField: "foo",
}

to := &struct {
unexportedField string
}{}

err := copier.Copy(to, from)
if err != nil {
t.Errorf("should not return an error")
return
}

if to.unexportedField != from.unexportedField {
t.Errorf("should be equal")
}
})

t.Run("should not copy unexported fields with disallowed by the option", func(t *testing.T) {
from := &struct {
unexportedField string
}{
unexportedField: "foo",
}

to := &struct {
unexportedField string
}{}

err := copier.CopyWithOption(to, from, optionsSkipUnexported)
if err != nil {
t.Errorf("should not return an error")
return
}

if to.unexportedField == from.unexportedField {
t.Errorf("should not be equal")
}
})
})
}

func TestMapInterface(t *testing.T) {
Expand Down

0 comments on commit c08cbc3

Please sign in to comment.