You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helm/internal/copystructure/copystructure_test.go

375 lines
8.3 KiB

/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package copystructure
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCopy_Nil(t *testing.T) {
result, err := Copy(nil)
require.NoError(t, err)
assert.Equal(t, map[string]any{}, result)
}
func TestCopy_PrimitiveTypes(t *testing.T) {
tests := []struct {
name string
input any
}{
{"bool", true},
{"int", 42},
{"int8", int8(8)},
{"int16", int16(16)},
{"int32", int32(32)},
{"int64", int64(64)},
{"uint", uint(42)},
{"uint8", uint8(8)},
{"uint16", uint16(16)},
{"uint32", uint32(32)},
{"uint64", uint64(64)},
{"float32", float32(3.14)},
{"float64", 3.14159},
{"complex64", complex64(1 + 2i)},
{"complex128", 1 + 2i},
{"string", "hello world"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := Copy(tt.input)
require.NoError(t, err)
assert.Equal(t, tt.input, result)
})
}
}
func TestCopy_Array(t *testing.T) {
input := [3]int{1, 2, 3}
result, err := Copy(input)
require.NoError(t, err)
assert.Equal(t, input, result)
}
func TestCopy_Slice(t *testing.T) {
t.Run("slice of ints", func(t *testing.T) {
input := []int{1, 2, 3, 4, 5}
result, err := Copy(input)
require.NoError(t, err)
resultSlice, ok := result.([]int)
require.True(t, ok)
assert.Equal(t, input, resultSlice)
// Verify it's a deep copy by modifying original
input[0] = 999
assert.Equal(t, 1, resultSlice[0])
})
t.Run("slice of strings", func(t *testing.T) {
input := []string{"a", "b", "c"}
result, err := Copy(input)
require.NoError(t, err)
assert.Equal(t, input, result)
})
t.Run("nil slice", func(t *testing.T) {
var input []int
result, err := Copy(input)
require.NoError(t, err)
assert.Nil(t, result)
})
t.Run("slice of maps", func(t *testing.T) {
input := []map[string]any{
{"key1": "value1"},
{"key2": "value2"},
}
result, err := Copy(input)
require.NoError(t, err)
resultSlice, ok := result.([]map[string]any)
require.True(t, ok)
assert.Equal(t, input, resultSlice)
// Verify deep copy
input[0]["key1"] = "modified"
assert.Equal(t, "value1", resultSlice[0]["key1"])
})
}
func TestCopy_Map(t *testing.T) {
t.Run("map[string]any", func(t *testing.T) {
input := map[string]any{
"string": "value",
"int": 42,
"bool": true,
"nested": map[string]any{
"inner": "value",
},
}
result, err := Copy(input)
require.NoError(t, err)
resultMap, ok := result.(map[string]any)
require.True(t, ok)
assert.Equal(t, input, resultMap)
// Verify deep copy
input["string"] = "modified"
assert.Equal(t, "value", resultMap["string"])
nestedInput := input["nested"].(map[string]any)
nestedResult := resultMap["nested"].(map[string]any)
nestedInput["inner"] = "modified"
assert.Equal(t, "value", nestedResult["inner"])
})
t.Run("map[string]string", func(t *testing.T) {
input := map[string]string{
"key1": "value1",
"key2": "value2",
}
result, err := Copy(input)
require.NoError(t, err)
assert.Equal(t, input, result)
})
t.Run("nil map", func(t *testing.T) {
var input map[string]any
result, err := Copy(input)
require.NoError(t, err)
assert.Nil(t, result)
})
t.Run("map with nil values", func(t *testing.T) {
input := map[string]any{
"key1": "value1",
"key2": nil,
}
result, err := Copy(input)
require.NoError(t, err)
resultMap, ok := result.(map[string]any)
require.True(t, ok)
assert.Equal(t, input, resultMap)
assert.Nil(t, resultMap["key2"])
})
}
func TestCopy_Struct(t *testing.T) {
type TestStruct struct {
Name string
Age int
Active bool
Scores []int
Metadata map[string]any
}
input := TestStruct{
Name: "John",
Age: 30,
Active: true,
Scores: []int{95, 87, 92},
Metadata: map[string]any{
"level": "advanced",
"tags": []string{"go", "programming"},
},
}
result, err := Copy(input)
require.NoError(t, err)
resultStruct, ok := result.(TestStruct)
require.True(t, ok)
assert.Equal(t, input, resultStruct)
// Verify deep copy
input.Name = "Modified"
input.Scores[0] = 999
assert.Equal(t, "John", resultStruct.Name)
assert.Equal(t, 95, resultStruct.Scores[0])
}
func TestCopy_Pointer(t *testing.T) {
t.Run("pointer to int", func(t *testing.T) {
value := 42
input := &value
result, err := Copy(input)
require.NoError(t, err)
resultPtr, ok := result.(*int)
require.True(t, ok)
assert.Equal(t, *input, *resultPtr)
// Verify they point to different memory locations
assert.NotSame(t, input, resultPtr)
// Verify deep copy
*input = 999
assert.Equal(t, 42, *resultPtr)
})
t.Run("pointer to struct", func(t *testing.T) {
type Person struct {
Name string
Age int
}
input := &Person{Name: "Alice", Age: 25}
result, err := Copy(input)
require.NoError(t, err)
resultPtr, ok := result.(*Person)
require.True(t, ok)
assert.Equal(t, *input, *resultPtr)
assert.NotSame(t, input, resultPtr)
})
t.Run("nil pointer", func(t *testing.T) {
var input *int
result, err := Copy(input)
require.NoError(t, err)
assert.Nil(t, result)
})
}
func TestCopy_Interface(t *testing.T) {
t.Run("any with value", func(t *testing.T) {
var input any = "hello"
result, err := Copy(input)
require.NoError(t, err)
assert.Equal(t, input, result)
})
t.Run("nil any", func(t *testing.T) {
var input any
result, err := Copy(input)
require.NoError(t, err)
// Copy(nil) returns an empty map according to the implementation
assert.Equal(t, map[string]any{}, result)
})
t.Run("any with complex value", func(t *testing.T) {
var input any = map[string]any{
"key": "value",
"nested": map[string]any{
"inner": 42,
},
}
result, err := Copy(input)
require.NoError(t, err)
assert.Equal(t, input, result)
})
}
func TestCopy_ComplexNested(t *testing.T) {
input := map[string]any{
"users": []map[string]any{
{
"name": "Alice",
"age": 30,
"addresses": []map[string]any{
{"type": "home", "city": "NYC"},
{"type": "work", "city": "SF"},
},
},
{
"name": "Bob",
"age": 25,
"addresses": []map[string]any{
{"type": "home", "city": "LA"},
},
},
},
"metadata": map[string]any{
"version": "1.0",
"flags": []bool{true, false, true},
},
}
result, err := Copy(input)
require.NoError(t, err)
resultMap, ok := result.(map[string]any)
require.True(t, ok)
assert.Equal(t, input, resultMap)
// Verify deep copy by modifying nested values
users := input["users"].([]map[string]any)
addresses := users[0]["addresses"].([]map[string]any)
addresses[0]["city"] = "Modified"
resultUsers := resultMap["users"].([]map[string]any)
resultAddresses := resultUsers[0]["addresses"].([]map[string]any)
assert.Equal(t, "NYC", resultAddresses[0]["city"])
}
func TestCopy_Functions(t *testing.T) {
t.Run("function", func(t *testing.T) {
input := func() string { return "hello" }
result, err := Copy(input)
require.NoError(t, err)
// Functions should be copied as-is (same reference)
resultFunc, ok := result.(func() string)
require.True(t, ok)
assert.Equal(t, input(), resultFunc())
})
t.Run("nil function", func(t *testing.T) {
var input func()
result, err := Copy(input)
require.NoError(t, err)
assert.Nil(t, result)
})
}
func TestCopy_Channels(t *testing.T) {
t.Run("channel", func(t *testing.T) {
input := make(chan int, 1)
input <- 42
result, err := Copy(input)
require.NoError(t, err)
// Channels should be copied as-is (same reference)
resultChan, ok := result.(chan int)
require.True(t, ok)
// Since channels are copied as references, verify we can read from the result channel
value := <-resultChan
assert.Equal(t, 42, value)
})
t.Run("nil channel", func(t *testing.T) {
var input chan int
result, err := Copy(input)
require.NoError(t, err)
assert.Nil(t, result)
})
}