• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package proptools
16
17import (
18	"fmt"
19	"reflect"
20	"testing"
21)
22
23var clonePropertiesTestCases = []struct {
24	in  interface{}
25	out interface{}
26	err error
27}{
28	// Valid inputs
29
30	{
31		// Clone bool
32		in: &struct{ B1, B2 bool }{
33			B1: true,
34			B2: false,
35		},
36		out: &struct{ B1, B2 bool }{
37			B1: true,
38			B2: false,
39		},
40	},
41	{
42		// Clone strings
43		in: &struct{ S string }{
44			S: "string1",
45		},
46		out: &struct{ S string }{
47			S: "string1",
48		},
49	},
50	{
51		// Clone slice
52		in: &struct{ S []string }{
53			S: []string{"string1"},
54		},
55		out: &struct{ S []string }{
56			S: []string{"string1"},
57		},
58	},
59	{
60		// Clone empty slice
61		in: &struct{ S []string }{
62			S: []string{},
63		},
64		out: &struct{ S []string }{
65			S: []string{},
66		},
67	},
68	{
69		// Clone nil slice
70		in:  &struct{ S []string }{},
71		out: &struct{ S []string }{},
72	},
73	{
74		// Clone slice of structs
75		in: &struct{ S []struct{ T string } }{
76			S: []struct{ T string }{
77				{"string1"}, {"string2"},
78			},
79		},
80		out: &struct{ S []struct{ T string } }{
81			S: []struct{ T string }{
82				{"string1"}, {"string2"},
83			},
84		},
85	},
86	{
87		// Clone map
88		in: &struct{ S map[string]string }{
89			S: map[string]string{"key": "string1"},
90		},
91		out: &struct{ S map[string]string }{
92			S: map[string]string{"key": "string1"},
93		},
94	},
95	{
96		// Clone empty map
97		in: &struct{ S map[string]string }{
98			S: map[string]string{},
99		},
100		out: &struct{ S map[string]string }{
101			S: map[string]string{},
102		},
103	},
104	{
105		// Clone nil map
106		in:  &struct{ S map[string]string }{},
107		out: &struct{ S map[string]string }{},
108	},
109	{
110		// Clone pointer to bool
111		in: &struct{ B1, B2 *bool }{
112			B1: BoolPtr(true),
113			B2: BoolPtr(false),
114		},
115		out: &struct{ B1, B2 *bool }{
116			B1: BoolPtr(true),
117			B2: BoolPtr(false),
118		},
119	},
120	{
121		// Clone pointer to string
122		in: &struct{ S *string }{
123			S: StringPtr("string1"),
124		},
125		out: &struct{ S *string }{
126			S: StringPtr("string1"),
127		},
128	},
129	{
130		// Clone pointer to int64
131		in: &struct{ S *int64 }{
132			S: Int64Ptr(5),
133		},
134		out: &struct{ S *int64 }{
135			S: Int64Ptr(5),
136		},
137	},
138	{
139		// Clone struct
140		in: &struct{ S struct{ S string } }{
141			S: struct{ S string }{
142				S: "string1",
143			},
144		},
145		out: &struct{ S struct{ S string } }{
146			S: struct{ S string }{
147				S: "string1",
148			},
149		},
150	},
151	{
152		// Clone struct pointer
153		in: &struct{ S *struct{ S string } }{
154			S: &struct{ S string }{
155				S: "string1",
156			},
157		},
158		out: &struct{ S *struct{ S string } }{
159			S: &struct{ S string }{
160				S: "string1",
161			},
162		},
163	},
164	{
165		// Clone interface
166		in: &struct{ S interface{} }{
167			S: &struct{ S string }{
168				S: "string1",
169			},
170		},
171		out: &struct{ S interface{} }{
172			S: &struct{ S string }{
173				S: "string1",
174			},
175		},
176	},
177	{
178		// Clone nested interface
179		in: &struct {
180			Nested struct{ S interface{} }
181		}{
182			Nested: struct{ S interface{} }{
183				S: &struct{ S string }{
184					S: "string1",
185				},
186			},
187		},
188		out: &struct {
189			Nested struct{ S interface{} }
190		}{
191			Nested: struct{ S interface{} }{
192				S: &struct{ S string }{
193					S: "string1",
194				},
195			},
196		},
197	}, {
198		// Empty struct
199		in:  &struct{}{},
200		out: &struct{}{},
201	},
202	{
203		// Interface nil
204		in: &struct{ S interface{} }{
205			S: nil,
206		},
207		out: &struct{ S interface{} }{
208			S: nil,
209		},
210	},
211	{
212		// Interface pointer to nil
213		in: &struct{ S interface{} }{
214			S: (*struct{ S string })(nil),
215		},
216		out: &struct{ S interface{} }{
217			S: (*struct{ S string })(nil),
218		},
219	},
220	{
221		// Pointer nil
222		in: &struct{ S *struct{} }{
223			S: nil,
224		},
225		out: &struct{ S *struct{} }{
226			S: nil,
227		},
228	},
229	{
230		// Anonymous struct
231		in: &struct {
232			EmbeddedStruct
233			Nested struct{ EmbeddedStruct }
234		}{
235			EmbeddedStruct: EmbeddedStruct{
236				S: "string1",
237				I: Int64Ptr(55),
238			},
239			Nested: struct{ EmbeddedStruct }{
240				EmbeddedStruct: EmbeddedStruct{
241					S: "string2",
242					I: Int64Ptr(5),
243				},
244			},
245		},
246		out: &struct {
247			EmbeddedStruct
248			Nested struct{ EmbeddedStruct }
249		}{
250			EmbeddedStruct: EmbeddedStruct{
251				S: "string1",
252				I: Int64Ptr(55),
253			},
254			Nested: struct{ EmbeddedStruct }{
255				EmbeddedStruct: EmbeddedStruct{
256					S: "string2",
257					I: Int64Ptr(5),
258				},
259			},
260		},
261	},
262	{
263		// Anonymous interface
264		in: &struct {
265			EmbeddedInterface
266			Nested struct{ EmbeddedInterface }
267		}{
268			EmbeddedInterface: &struct{ S string }{
269				S: "string1",
270			},
271			Nested: struct{ EmbeddedInterface }{
272				EmbeddedInterface: &struct{ S string }{
273					S: "string2",
274				},
275			},
276		},
277		out: &struct {
278			EmbeddedInterface
279			Nested struct{ EmbeddedInterface }
280		}{
281			EmbeddedInterface: &struct{ S string }{
282				S: "string1",
283			},
284			Nested: struct{ EmbeddedInterface }{
285				EmbeddedInterface: &struct{ S string }{
286					S: "string2",
287				},
288			},
289		},
290	},
291}
292
293type EmbeddedStruct struct {
294	S string
295	I *int64
296}
297type EmbeddedInterface interface{}
298
299func TestCloneProperties(t *testing.T) {
300	for _, testCase := range clonePropertiesTestCases {
301		testString := fmt.Sprintf("%s", testCase.in)
302
303		got := CloneProperties(reflect.ValueOf(testCase.in)).Interface()
304
305		if !reflect.DeepEqual(testCase.out, got) {
306			t.Errorf("test case %s", testString)
307			t.Errorf("incorrect output")
308			t.Errorf("  expected: %#v", testCase.out)
309			t.Errorf("       got: %#v", got)
310		}
311		if testCase.out == got {
312			t.Errorf("test case %s", testString)
313			t.Errorf("items should be cloned, not the original")
314			t.Errorf("  expected: %s", testCase.out)
315			t.Errorf("       got: %s", got)
316		}
317	}
318}
319
320var cloneEmptyPropertiesTestCases = []struct {
321	in  interface{}
322	out interface{}
323	err error
324}{
325	// Valid inputs
326
327	{
328		// Clone bool
329		in: &struct{ B1, B2 bool }{
330			B1: true,
331			B2: false,
332		},
333		out: &struct{ B1, B2 bool }{},
334	},
335	{
336		// Clone strings
337		in: &struct{ S string }{
338			S: "string1",
339		},
340		out: &struct{ S string }{},
341	},
342	{
343		// Clone slice
344		in: &struct{ S []string }{
345			S: []string{"string1"},
346		},
347		out: &struct{ S []string }{},
348	},
349	{
350		// Clone empty slice
351		in: &struct{ S []string }{
352			S: []string{},
353		},
354		out: &struct{ S []string }{},
355	},
356	{
357		// Clone nil slice
358		in:  &struct{ S []string }{},
359		out: &struct{ S []string }{},
360	},
361	{
362		// Clone slice of structs
363		in: &struct{ S []struct{ T string } }{
364			S: []struct{ T string }{
365				{"string1"}, {"string2"},
366			},
367		},
368		out: &struct{ S []struct{ T string } }{
369			S: []struct{ T string }(nil),
370		},
371	},
372	{
373		// Clone pointer to bool
374		in: &struct{ B1, B2 *bool }{
375			B1: BoolPtr(true),
376			B2: BoolPtr(false),
377		},
378		out: &struct{ B1, B2 *bool }{},
379	},
380	{
381		// Clone pointer to int64
382		in: &struct{ B1, B2 *int64 }{
383			B1: Int64Ptr(5),
384			B2: Int64Ptr(4),
385		},
386		out: &struct{ B1, B2 *int64 }{},
387	},
388	{
389		// Clone pointer to string
390		in: &struct{ S *string }{
391			S: StringPtr("string1"),
392		},
393		out: &struct{ S *string }{},
394	},
395	{
396		// Clone struct
397		in: &struct{ S struct{ S string } }{
398			S: struct{ S string }{
399				S: "string1",
400			},
401		},
402		out: &struct{ S struct{ S string } }{
403			S: struct{ S string }{},
404		},
405	},
406	{
407		// Clone struct pointer
408		in: &struct{ S *struct{ S string } }{
409			S: &struct{ S string }{
410				S: "string1",
411			},
412		},
413		out: &struct{ S *struct{ S string } }{
414			S: &struct{ S string }{},
415		},
416	},
417	{
418		// Clone interface
419		in: &struct{ S interface{} }{
420			S: &struct{ S string }{
421				S: "string1",
422			},
423		},
424		out: &struct{ S interface{} }{
425			S: &struct{ S string }{},
426		},
427	},
428	{
429		// Clone nested interface
430		in: &struct {
431			Nested struct{ S interface{} }
432		}{
433			Nested: struct{ S interface{} }{
434				S: &struct{ S string }{
435					S: "string1",
436				},
437			},
438		},
439		out: &struct {
440			Nested struct{ S interface{} }
441		}{
442			Nested: struct{ S interface{} }{
443				S: &struct{ S string }{},
444			},
445		},
446	},
447	{
448		// Empty struct
449		in:  &struct{}{},
450		out: &struct{}{},
451	},
452	{
453		// Interface nil
454		in: &struct{ S interface{} }{
455			S: nil,
456		},
457		out: &struct{ S interface{} }{},
458	},
459	{
460		// Interface pointer to nil
461		in: &struct{ S interface{} }{
462			S: (*struct{ S string })(nil),
463		},
464		out: &struct{ S interface{} }{
465			S: (*struct{ S string })(nil),
466		},
467	},
468	{
469		// Pointer nil
470		in: &struct{ S *struct{} }{
471			S: nil,
472		},
473		out: &struct{ S *struct{} }{},
474	},
475	{
476		// Anonymous struct
477		in: &struct {
478			EmbeddedStruct
479			Nested struct{ EmbeddedStruct }
480		}{
481			EmbeddedStruct: EmbeddedStruct{
482				S: "string1",
483			},
484			Nested: struct{ EmbeddedStruct }{
485				EmbeddedStruct: EmbeddedStruct{
486					S: "string2",
487				},
488			},
489		},
490		out: &struct {
491			EmbeddedStruct
492			Nested struct{ EmbeddedStruct }
493		}{
494			EmbeddedStruct: EmbeddedStruct{},
495			Nested: struct{ EmbeddedStruct }{
496				EmbeddedStruct: EmbeddedStruct{},
497			},
498		},
499	},
500	{
501		// Anonymous interface
502		in: &struct {
503			EmbeddedInterface
504			Nested struct{ EmbeddedInterface }
505		}{
506			EmbeddedInterface: &struct{ S string }{
507				S: "string1",
508			},
509			Nested: struct{ EmbeddedInterface }{
510				EmbeddedInterface: &struct{ S string }{
511					S: "string2",
512				},
513			},
514		},
515		out: &struct {
516			EmbeddedInterface
517			Nested struct{ EmbeddedInterface }
518		}{
519			EmbeddedInterface: &struct{ S string }{},
520			Nested: struct{ EmbeddedInterface }{
521				EmbeddedInterface: &struct{ S string }{},
522			},
523		},
524	},
525}
526
527func TestCloneEmptyProperties(t *testing.T) {
528	for _, testCase := range cloneEmptyPropertiesTestCases {
529		testString := fmt.Sprintf("%#v", testCase.in)
530
531		got := CloneEmptyProperties(reflect.ValueOf(testCase.in)).Interface()
532
533		if !reflect.DeepEqual(testCase.out, got) {
534			t.Errorf("test case %s", testString)
535			t.Errorf("incorrect output")
536			t.Errorf("  expected: %#v", testCase.out)
537			t.Errorf("       got: %#v", got)
538		}
539	}
540}
541
542func TestZeroProperties(t *testing.T) {
543	for _, testCase := range cloneEmptyPropertiesTestCases {
544		testString := fmt.Sprintf("%#v", testCase.in)
545
546		got := CloneProperties(reflect.ValueOf(testCase.in)).Interface()
547		ZeroProperties(reflect.ValueOf(got))
548
549		if !reflect.DeepEqual(testCase.out, got) {
550			t.Errorf("test case %s", testString)
551			t.Errorf("incorrect output")
552			t.Errorf("  expected: %#v", testCase.out)
553			t.Errorf("       got: %#v", got)
554		}
555	}
556}
557