pull/32712/merge
Nitin Kumar Patel 1 day ago committed by GitHub
commit a8fa67d432
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -80,7 +80,7 @@ func copyValue(original reflect.Value) (any, error) {
return nil, err return nil, err
} }
ptr := reflect.New(original.Type().Elem()) ptr := reflect.New(original.Type().Elem())
ptr.Elem().Set(reflect.ValueOf(copied)) setValue(ptr.Elem(), copied)
return ptr.Interface(), nil return ptr.Interface(), nil
case reflect.Slice: case reflect.Slice:
@ -106,13 +106,20 @@ func copyValue(original reflect.Value) (any, error) {
return copied.Interface(), nil return copied.Interface(), nil
case reflect.Struct: case reflect.Struct:
copied := reflect.New(original.Type()).Elem() t := original.Type()
for field := range t.Fields() {
// Unexported fields can't be read or set through reflection.
if !field.IsExported() {
return nil, fmt.Errorf("unsupported type %v: struct with unexported fields", t)
}
}
copied := reflect.New(t).Elem()
for i := 0; i < original.NumField(); i++ { for i := 0; i < original.NumField(); i++ {
elem, err := copyValue(original.Field(i)) elem, err := copyValue(original.Field(i))
if err != nil { if err != nil {
return nil, err return nil, err
} }
copied.Field(i).Set(reflect.ValueOf(elem)) setValue(copied.Field(i), elem)
} }
return copied.Interface(), nil return copied.Interface(), nil
@ -126,3 +133,13 @@ func copyValue(original reflect.Value) (any, error) {
return original.Interface(), fmt.Errorf("unsupported type %v", original) return original.Interface(), fmt.Errorf("unsupported type %v", original)
} }
} }
// setValue sets dst to v. A nil v (the copy of a nil interface) is stored as
// the zero value of dst's type, since reflect.ValueOf(nil) can't be passed to Set.
func setValue(dst reflect.Value, v any) {
if v == nil {
dst.Set(reflect.Zero(dst.Type()))
return
}
dst.Set(reflect.ValueOf(v))
}

@ -18,6 +18,7 @@ package copystructure
import ( import (
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -193,6 +194,7 @@ func TestCopy_Map(t *testing.T) {
} }
func TestCopy_Struct(t *testing.T) { func TestCopy_Struct(t *testing.T) {
t.Run("exported fields", func(t *testing.T) {
type TestStruct struct { type TestStruct struct {
Name string Name string
Age int Age int
@ -224,6 +226,35 @@ func TestCopy_Struct(t *testing.T) {
input.Scores[0] = 999 input.Scores[0] = 999
assert.Equal(t, "John", resultStruct.Name) assert.Equal(t, "John", resultStruct.Name)
assert.Equal(t, 95, resultStruct.Scores[0]) assert.Equal(t, 95, resultStruct.Scores[0])
})
t.Run("nil interface field", func(t *testing.T) {
type WithAny struct {
Name string
Extra any
}
input := map[string]any{"s": WithAny{Name: "a"}}
result, err := Copy(input)
require.NoError(t, err)
assert.Equal(t, input, result)
})
t.Run("unexported fields", func(t *testing.T) {
type withUnexported struct {
Name string
secret int
}
_, err := Copy(map[string]any{"s": withUnexported{Name: "a", secret: 1}})
require.Error(t, err)
})
t.Run("time.Time", func(t *testing.T) {
_, err := Copy(map[string]any{"t": time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)})
require.Error(t, err)
})
} }
func TestCopy_Pointer(t *testing.T) { func TestCopy_Pointer(t *testing.T) {
@ -269,6 +300,18 @@ func TestCopy_Pointer(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, result) assert.Nil(t, result)
}) })
t.Run("pointer to nil interface", func(t *testing.T) {
var value any
result, err := Copy(&value)
require.NoError(t, err)
resultPtr, ok := result.(*any)
require.True(t, ok)
assert.Nil(t, *resultPtr)
assert.NotSame(t, &value, resultPtr)
})
} }
func TestCopy_Interface(t *testing.T) { func TestCopy_Interface(t *testing.T) {

@ -329,6 +329,13 @@ func TestInstallRelease_NoName(t *testing.T) {
assert.ErrorContains(t, err, "no name provided") assert.ErrorContains(t, err, "no name provided")
} }
func TestInstallRelease_UnsupportedValueType(t *testing.T) {
instAction := installAction(t)
vals := map[string]any{"deployedAt": time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)}
_, err := instAction.Run(buildChart(), vals)
assert.ErrorContains(t, err, "struct with unexported fields")
}
func TestInstallRelease_WithNotes(t *testing.T) { func TestInstallRelease_WithNotes(t *testing.T) {
is := assert.New(t) is := assert.New(t)
req := require.New(t) req := require.New(t)

Loading…
Cancel
Save