mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Add DeepCopy! Also-- optimize conversion for []byte
This commit is contained in:
		| @@ -71,7 +71,7 @@ type Converter struct { | |||||||
|  |  | ||||||
| // NewConverter creates a new Converter object. | // NewConverter creates a new Converter object. | ||||||
| func NewConverter() *Converter { | func NewConverter() *Converter { | ||||||
| 	return &Converter{ | 	c := &Converter{ | ||||||
| 		conversionFuncs:    map[typePair]reflect.Value{}, | 		conversionFuncs:    map[typePair]reflect.Value{}, | ||||||
| 		defaultingFuncs:    map[reflect.Type]reflect.Value{}, | 		defaultingFuncs:    map[reflect.Type]reflect.Value{}, | ||||||
| 		nameFunc:           func(t reflect.Type) string { return t.Name() }, | 		nameFunc:           func(t reflect.Type) string { return t.Name() }, | ||||||
| @@ -81,6 +81,15 @@ func NewConverter() *Converter { | |||||||
| 		inputFieldMappingFuncs: map[reflect.Type]FieldMappingFunc{}, | 		inputFieldMappingFuncs: map[reflect.Type]FieldMappingFunc{}, | ||||||
| 		inputDefaultFlags:      map[reflect.Type]FieldMatchingFlags{}, | 		inputDefaultFlags:      map[reflect.Type]FieldMatchingFlags{}, | ||||||
| 	} | 	} | ||||||
|  | 	c.RegisterConversionFunc(byteSliceCopy) | ||||||
|  | 	return c | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Prevent recursing into every byte... | ||||||
|  | func byteSliceCopy(in *[]byte, out *[]byte, s Scope) error { | ||||||
|  | 	*out = make([]byte, len(*in)) | ||||||
|  | 	copy(*out, *in) | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // Scope is passed to conversion funcs to allow them to continue an ongoing conversion. | // Scope is passed to conversion funcs to allow them to continue an ongoing conversion. | ||||||
|   | |||||||
| @@ -26,6 +26,19 @@ import ( | |||||||
| 	"github.com/google/gofuzz" | 	"github.com/google/gofuzz" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | func TestConverter_byteSlice(t *testing.T) { | ||||||
|  | 	c := NewConverter() | ||||||
|  | 	src := []byte{1, 2, 3} | ||||||
|  | 	dest := []byte{} | ||||||
|  | 	err := c.Convert(&src, &dest, 0, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("expected no error") | ||||||
|  | 	} | ||||||
|  | 	if e, a := src, dest; !reflect.DeepEqual(e, a) { | ||||||
|  | 		t.Errorf("expected %#v, got %#v", e, a) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestConverter_DefaultConvert(t *testing.T) { | func TestConverter_DefaultConvert(t *testing.T) { | ||||||
| 	type A struct { | 	type A struct { | ||||||
| 		Foo string | 		Foo string | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								pkg/conversion/deep_copy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								pkg/conversion/deep_copy.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | /* | ||||||
|  | Copyright 2015 Google Inc. All rights reserved. | ||||||
|  |  | ||||||
|  | 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 conversion | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var deepCopier = NewConverter() | ||||||
|  |  | ||||||
|  | // DeepCopy makes a deep copy of source. Won't work for any private fields! | ||||||
|  | // For nil slices, will return 0-length slices. These are equivilent in | ||||||
|  | // basically every way except for the way that reflect.DeepEqual checks. | ||||||
|  | func DeepCopy(source interface{}) (interface{}, error) { | ||||||
|  | 	src := reflect.ValueOf(source) | ||||||
|  | 	v := reflect.New(src.Type()).Elem() | ||||||
|  | 	s := &scope{ | ||||||
|  | 		converter: deepCopier, | ||||||
|  | 	} | ||||||
|  | 	if err := deepCopier.convert(src, v, s); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return v.Interface(), nil | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								pkg/conversion/deep_copy_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								pkg/conversion/deep_copy_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | /* | ||||||
|  | Copyright 2015 Google Inc. All rights reserved. | ||||||
|  |  | ||||||
|  | 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 conversion | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/google/gofuzz" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestDeepCopy(t *testing.T) { | ||||||
|  | 	semantic := EqualitiesOrDie() | ||||||
|  | 	f := fuzz.New().NilChance(.5).NumElements(0, 100) | ||||||
|  | 	table := []interface{}{ | ||||||
|  | 		map[string]string{}, | ||||||
|  | 		int(5), | ||||||
|  | 		"hello world", | ||||||
|  | 		struct { | ||||||
|  | 			A, B, C struct { | ||||||
|  | 				D map[string]int | ||||||
|  | 			} | ||||||
|  | 			X []int | ||||||
|  | 			Y []byte | ||||||
|  | 		}{}, | ||||||
|  | 	} | ||||||
|  | 	for _, obj := range table { | ||||||
|  | 		obj2, err := DeepCopy(obj) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Error: couldn't copy %#v", obj) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if e, a := obj, obj2; !semantic.DeepEqual(e, a) { | ||||||
|  | 			t.Errorf("expected %#v\ngot %#v", e, a) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		obj3 := reflect.New(reflect.TypeOf(obj)).Interface() | ||||||
|  | 		f.Fuzz(obj3) | ||||||
|  | 		obj4, err := DeepCopy(obj3) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Error: couldn't copy %#v", obj) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if e, a := obj3, obj4; !semantic.DeepEqual(e, a) { | ||||||
|  | 			t.Errorf("expected %#v\ngot %#v", e, a) | ||||||
|  | 		} | ||||||
|  | 		f.Fuzz(obj3) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyOrDie(t *testing.T, in interface{}) interface{} { | ||||||
|  | 	out, err := DeepCopy(in) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("DeepCopy failed: %#q: %v", in, err) | ||||||
|  | 	} | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDeepCopySliceSeparate(t *testing.T) { | ||||||
|  | 	x := []int{5} | ||||||
|  | 	y := copyOrDie(t, x).([]int) | ||||||
|  | 	x[0] = 3 | ||||||
|  | 	if y[0] == 3 { | ||||||
|  | 		t.Errorf("deep copy wasn't deep: %#q %#q", x, y) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDeepCopyArraySeparate(t *testing.T) { | ||||||
|  | 	x := [1]int{5} | ||||||
|  | 	y := copyOrDie(t, x).([1]int) | ||||||
|  | 	x[0] = 3 | ||||||
|  | 	if y[0] == 3 { | ||||||
|  | 		t.Errorf("deep copy wasn't deep: %#q %#q", x, y) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDeepCopyMapSeparate(t *testing.T) { | ||||||
|  | 	x := map[string]int{"foo": 5} | ||||||
|  | 	y := copyOrDie(t, x).(map[string]int) | ||||||
|  | 	x["foo"] = 3 | ||||||
|  | 	if y["foo"] == 3 { | ||||||
|  | 		t.Errorf("deep copy wasn't deep: %#q %#q", x, y) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDeepCopyPointerSeparate(t *testing.T) { | ||||||
|  | 	z := 5 | ||||||
|  | 	x := &z | ||||||
|  | 	y := copyOrDie(t, x).(*int) | ||||||
|  | 	*x = 3 | ||||||
|  | 	if *y == 3 { | ||||||
|  | 		t.Errorf("deep copy wasn't deep: %#q %#q", x, y) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -25,6 +25,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/GoogleCloudPlatform/kubernetes/pkg/api" | ||||||
| 	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" | 	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" | ||||||
| 	clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" | 	clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" | ||||||
| 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util" | 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util" | ||||||
| @@ -667,7 +668,7 @@ func (test configCommandTest) run(t *testing.T) string { | |||||||
| 	testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig)) | 	testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig)) | ||||||
| 	testClearLocationOfOrigin(&actualConfig) | 	testClearLocationOfOrigin(&actualConfig) | ||||||
|  |  | ||||||
| 	if !reflect.DeepEqual(test.expectedConfig, actualConfig) { | 	if !api.Semantic.DeepEqual(test.expectedConfig, actualConfig) { | ||||||
| 		t.Errorf("diff: %v", util.ObjectDiff(test.expectedConfig, actualConfig)) | 		t.Errorf("diff: %v", util.ObjectDiff(test.expectedConfig, actualConfig)) | ||||||
| 		t.Errorf("expected: %#v\n actual:   %#v", test.expectedConfig, actualConfig) | 		t.Errorf("expected: %#v\n actual:   %#v", test.expectedConfig, actualConfig) | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user