From e4a571f345fa5e490247a40766992a773df26c64 Mon Sep 17 00:00:00 2001 From: Nikhil Sinha Date: Mon, 28 Apr 2025 17:17:00 -0700 Subject: [PATCH 1/2] Add util function to copy fields between structs --- util/util.go | 23 +++++++ util/util_test.go | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 util/util.go create mode 100644 util/util_test.go diff --git a/util/util.go b/util/util.go new file mode 100644 index 0000000..1e5c400 --- /dev/null +++ b/util/util.go @@ -0,0 +1,23 @@ +package util + +import "reflect" + +// CopyFields copies any fields with the same name and type from one struct to another +func CopyFields[A any, B any](a *A, b *B) { + val := reflect.Indirect(reflect.ValueOf(a)) + val2 := reflect.Indirect(reflect.ValueOf(b)) + for i := 0; i < val.Type().NumField(); i++ { + name := val.Type().Field(i).Name + field := val2.FieldByName(name) + if !field.IsValid() { + continue + } + if val.Type().Field(i).Type != field.Type() { + continue + } + if !val.Type().Field(i).IsExported() { + continue + } + field.Set(reflect.Indirect(reflect.ValueOf(a)).FieldByName(name)) + } +} diff --git a/util/util_test.go b/util/util_test.go new file mode 100644 index 0000000..42ca0dc --- /dev/null +++ b/util/util_test.go @@ -0,0 +1,160 @@ +package util + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCopyFields_Normal(t *testing.T) { + type a struct { + Thing int + AnotherThing string + OneMoreThing bool + } + + type b struct { + Thing int + AnotherThing string + } + + thing1 := &a{ + Thing: 123, + AnotherThing: "abc", + OneMoreThing: false, + } + + thing2 := &b{} + + CopyFields(thing1, thing2) + assert.Equal(t, thing2.Thing, 123) + assert.Equal(t, thing2.AnotherThing, "abc") +} + +func TestCopyFields_Unexported(t *testing.T) { + type a struct { + thing int + anotherThing string + oneMoreThing bool + } + + type b struct { + thing int + anotherThing string + } + + thing1 := &a{ + thing: 123, + anotherThing: "abc", + oneMoreThing: false, + } + + thing2 := &b{} + + CopyFields(thing1, thing2) + assert.Equal(t, thing2.thing, 0) + assert.Equal(t, thing2.anotherThing, "") +} + +func TestCopyFields_DifferentType(t *testing.T) { + type a struct { + Thing int + AnotherThing string + OneMoreThing bool + } + + type b struct { + Thing int + AnotherThing string + OneMoreThing string + } + + thing1 := &a{ + Thing: 123, + AnotherThing: "abc", + OneMoreThing: false, + } + + thing2 := &b{} + + CopyFields(thing1, thing2) + assert.Equal(t, thing2.Thing, 123) + assert.Equal(t, thing2.AnotherThing, "abc") + assert.Equal(t, thing2.OneMoreThing, "") +} + +func TestCopyFields_UnexportedReceiver(t *testing.T) { + type a struct { + Thing int + AnotherThing string + OneMoreThing bool + } + + type b struct { + thing int + anotherThing string + } + + thing1 := &a{ + Thing: 123, + AnotherThing: "abc", + OneMoreThing: false, + } + + thing2 := &b{} + + CopyFields(thing1, thing2) + assert.Equal(t, thing2.thing, 0) + assert.Equal(t, thing2.anotherThing, "") +} + +func TestCopyFields_RefField(t *testing.T) { + type a struct { + Thing map[string]string + AnotherThing string + } + + type b struct { + Thing map[string]string + } + + thing1 := &a{ + Thing: map[string]string{ + "a": "b", + "c": "d", + }, + } + + thing2 := &b{} + + CopyFields(thing1, thing2) + assert.Equal(t, thing2.Thing, map[string]string{ + "a": "b", + "c": "d", + }) +} + +func TestCopyFields_Func(t *testing.T) { + type a struct { + Thing func(int) string + AnotherThing int + } + + type b struct { + Thing func(int) string + AnotherThing string + } + + thing1 := &a{ + Thing: func(i int) string { + return fmt.Sprintf("hello %d", i) + }, + } + + thing2 := &b{} + + CopyFields(thing1, thing2) + assert.Equal(t, thing2.Thing(123), "hello 123") + assert.Equal(t, thing2.AnotherThing, "") +} From 3fd2d90d431db95146c52759d1552d320c5b6151 Mon Sep 17 00:00:00 2001 From: Nikhil Sinha Date: Mon, 28 Apr 2025 17:27:45 -0700 Subject: [PATCH 2/2] Rename files --- util/{util.go => copy.go} | 0 util/{util_test.go => copy_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename util/{util.go => copy.go} (100%) rename util/{util_test.go => copy_test.go} (100%) diff --git a/util/util.go b/util/copy.go similarity index 100% rename from util/util.go rename to util/copy.go diff --git a/util/util_test.go b/util/copy_test.go similarity index 100% rename from util/util_test.go rename to util/copy_test.go