• 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 pointer to bool
75		in: &struct{ B1, B2 *bool }{
76			B1: BoolPtr(true),
77			B2: BoolPtr(false),
78		},
79		out: &struct{ B1, B2 *bool }{
80			B1: BoolPtr(true),
81			B2: BoolPtr(false),
82		},
83	},
84	{
85		// Clone pointer to string
86		in: &struct{ S *string }{
87			S: StringPtr("string1"),
88		},
89		out: &struct{ S *string }{
90			S: StringPtr("string1"),
91		},
92	},
93	{
94		// Clone struct
95		in: &struct{ S struct{ S string } }{
96			S: struct{ S string }{
97				S: "string1",
98			},
99		},
100		out: &struct{ S struct{ S string } }{
101			S: struct{ S string }{
102				S: "string1",
103			},
104		},
105	},
106	{
107		// Clone struct pointer
108		in: &struct{ S *struct{ S string } }{
109			S: &struct{ S string }{
110				S: "string1",
111			},
112		},
113		out: &struct{ S *struct{ S string } }{
114			S: &struct{ S string }{
115				S: "string1",
116			},
117		},
118	},
119	{
120		// Clone interface
121		in: &struct{ S interface{} }{
122			S: &struct{ S string }{
123				S: "string1",
124			},
125		},
126		out: &struct{ S interface{} }{
127			S: &struct{ S string }{
128				S: "string1",
129			},
130		},
131	},
132	{
133		// Clone nested interface
134		in: &struct {
135			Nested struct{ S interface{} }
136		}{
137			Nested: struct{ S interface{} }{
138				S: &struct{ S string }{
139					S: "string1",
140				},
141			},
142		},
143		out: &struct {
144			Nested struct{ S interface{} }
145		}{
146			Nested: struct{ S interface{} }{
147				S: &struct{ S string }{
148					S: "string1",
149				},
150			},
151		},
152	}, {
153		// Empty struct
154		in:  &struct{}{},
155		out: &struct{}{},
156	},
157	{
158		// Interface nil
159		in: &struct{ S interface{} }{
160			S: nil,
161		},
162		out: &struct{ S interface{} }{
163			S: nil,
164		},
165	},
166	{
167		// Interface pointer to nil
168		in: &struct{ S interface{} }{
169			S: (*struct{ S string })(nil),
170		},
171		out: &struct{ S interface{} }{
172			S: (*struct{ S string })(nil),
173		},
174	},
175	{
176		// Pointer nil
177		in: &struct{ S *struct{} }{
178			S: nil,
179		},
180		out: &struct{ S *struct{} }{
181			S: nil,
182		},
183	},
184	{
185		// Anonymous struct
186		in: &struct {
187			EmbeddedStruct
188			Nested struct{ EmbeddedStruct }
189		}{
190			EmbeddedStruct: EmbeddedStruct{
191				S: "string1",
192			},
193			Nested: struct{ EmbeddedStruct }{
194				EmbeddedStruct: EmbeddedStruct{
195					S: "string2",
196				},
197			},
198		},
199		out: &struct {
200			EmbeddedStruct
201			Nested struct{ EmbeddedStruct }
202		}{
203			EmbeddedStruct: EmbeddedStruct{
204				S: "string1",
205			},
206			Nested: struct{ EmbeddedStruct }{
207				EmbeddedStruct: EmbeddedStruct{
208					S: "string2",
209				},
210			},
211		},
212	},
213	{
214		// Anonymous interface
215		in: &struct {
216			EmbeddedInterface
217			Nested struct{ EmbeddedInterface }
218		}{
219			EmbeddedInterface: &struct{ S string }{
220				S: "string1",
221			},
222			Nested: struct{ EmbeddedInterface }{
223				EmbeddedInterface: &struct{ S string }{
224					S: "string2",
225				},
226			},
227		},
228		out: &struct {
229			EmbeddedInterface
230			Nested struct{ EmbeddedInterface }
231		}{
232			EmbeddedInterface: &struct{ S string }{
233				S: "string1",
234			},
235			Nested: struct{ EmbeddedInterface }{
236				EmbeddedInterface: &struct{ S string }{
237					S: "string2",
238				},
239			},
240		},
241	},
242}
243
244type EmbeddedStruct struct{ S string }
245type EmbeddedInterface interface{}
246
247func TestCloneProperties(t *testing.T) {
248	for _, testCase := range clonePropertiesTestCases {
249		testString := fmt.Sprintf("%s", testCase.in)
250
251		got := CloneProperties(reflect.ValueOf(testCase.in).Elem()).Interface()
252
253		if !reflect.DeepEqual(testCase.out, got) {
254			t.Errorf("test case %s", testString)
255			t.Errorf("incorrect output")
256			t.Errorf("  expected: %#v", testCase.out)
257			t.Errorf("       got: %#v", got)
258		}
259	}
260}
261
262var cloneEmptyPropertiesTestCases = []struct {
263	in  interface{}
264	out interface{}
265	err error
266}{
267	// Valid inputs
268
269	{
270		// Clone bool
271		in: &struct{ B1, B2 bool }{
272			B1: true,
273			B2: false,
274		},
275		out: &struct{ B1, B2 bool }{},
276	},
277	{
278		// Clone strings
279		in: &struct{ S string }{
280			S: "string1",
281		},
282		out: &struct{ S string }{},
283	},
284	{
285		// Clone slice
286		in: &struct{ S []string }{
287			S: []string{"string1"},
288		},
289		out: &struct{ S []string }{},
290	},
291	{
292		// Clone empty slice
293		in: &struct{ S []string }{
294			S: []string{},
295		},
296		out: &struct{ S []string }{},
297	},
298	{
299		// Clone nil slice
300		in:  &struct{ S []string }{},
301		out: &struct{ S []string }{},
302	},
303	{
304		// Clone pointer to bool
305		in: &struct{ B1, B2 *bool }{
306			B1: BoolPtr(true),
307			B2: BoolPtr(false),
308		},
309		out: &struct{ B1, B2 *bool }{},
310	},
311	{
312		// Clone pointer to string
313		in: &struct{ S *string }{
314			S: StringPtr("string1"),
315		},
316		out: &struct{ S *string }{},
317	},
318	{
319		// Clone struct
320		in: &struct{ S struct{ S string } }{
321			S: struct{ S string }{
322				S: "string1",
323			},
324		},
325		out: &struct{ S struct{ S string } }{
326			S: struct{ S string }{},
327		},
328	},
329	{
330		// Clone struct pointer
331		in: &struct{ S *struct{ S string } }{
332			S: &struct{ S string }{
333				S: "string1",
334			},
335		},
336		out: &struct{ S *struct{ S string } }{
337			S: &struct{ S string }{},
338		},
339	},
340	{
341		// Clone interface
342		in: &struct{ S interface{} }{
343			S: &struct{ S string }{
344				S: "string1",
345			},
346		},
347		out: &struct{ S interface{} }{
348			S: &struct{ S string }{},
349		},
350	},
351	{
352		// Clone nested interface
353		in: &struct {
354			Nested struct{ S interface{} }
355		}{
356			Nested: struct{ S interface{} }{
357				S: &struct{ S string }{
358					S: "string1",
359				},
360			},
361		},
362		out: &struct {
363			Nested struct{ S interface{} }
364		}{
365			Nested: struct{ S interface{} }{
366				S: &struct{ S string }{},
367			},
368		},
369	},
370	{
371		// Empty struct
372		in:  &struct{}{},
373		out: &struct{}{},
374	},
375	{
376		// Interface nil
377		in: &struct{ S interface{} }{
378			S: nil,
379		},
380		out: &struct{ S interface{} }{},
381	},
382	{
383		// Interface pointer to nil
384		in: &struct{ S interface{} }{
385			S: (*struct{ S string })(nil),
386		},
387		out: &struct{ S interface{} }{
388			S: (*struct{ S string })(nil),
389		},
390	},
391	{
392		// Pointer nil
393		in: &struct{ S *struct{} }{
394			S: nil,
395		},
396		out: &struct{ S *struct{} }{},
397	},
398	{
399		// Anonymous struct
400		in: &struct {
401			EmbeddedStruct
402			Nested struct{ EmbeddedStruct }
403		}{
404			EmbeddedStruct: EmbeddedStruct{
405				S: "string1",
406			},
407			Nested: struct{ EmbeddedStruct }{
408				EmbeddedStruct: EmbeddedStruct{
409					S: "string2",
410				},
411			},
412		},
413		out: &struct {
414			EmbeddedStruct
415			Nested struct{ EmbeddedStruct }
416		}{
417			EmbeddedStruct: EmbeddedStruct{},
418			Nested: struct{ EmbeddedStruct }{
419				EmbeddedStruct: EmbeddedStruct{},
420			},
421		},
422	},
423	{
424		// Anonymous interface
425		in: &struct {
426			EmbeddedInterface
427			Nested struct{ EmbeddedInterface }
428		}{
429			EmbeddedInterface: &struct{ S string }{
430				S: "string1",
431			},
432			Nested: struct{ EmbeddedInterface }{
433				EmbeddedInterface: &struct{ S string }{
434					S: "string2",
435				},
436			},
437		},
438		out: &struct {
439			EmbeddedInterface
440			Nested struct{ EmbeddedInterface }
441		}{
442			EmbeddedInterface: &struct{ S string }{},
443			Nested: struct{ EmbeddedInterface }{
444				EmbeddedInterface: &struct{ S string }{},
445			},
446		},
447	},
448}
449
450func TestCloneEmptyProperties(t *testing.T) {
451	for _, testCase := range cloneEmptyPropertiesTestCases {
452		testString := fmt.Sprintf("%#v", testCase.in)
453
454		got := CloneEmptyProperties(reflect.ValueOf(testCase.in).Elem()).Interface()
455
456		if !reflect.DeepEqual(testCase.out, got) {
457			t.Errorf("test case %s", testString)
458			t.Errorf("incorrect output")
459			t.Errorf("  expected: %#v", testCase.out)
460			t.Errorf("       got: %#v", got)
461		}
462	}
463}
464
465func TestZeroProperties(t *testing.T) {
466	for _, testCase := range cloneEmptyPropertiesTestCases {
467		testString := fmt.Sprintf("%#v", testCase.in)
468
469		got := CloneProperties(reflect.ValueOf(testCase.in).Elem()).Interface()
470		ZeroProperties(reflect.ValueOf(got).Elem())
471
472		if !reflect.DeepEqual(testCase.out, got) {
473			t.Errorf("test case %s", testString)
474			t.Errorf("incorrect output")
475			t.Errorf("  expected: %#v", testCase.out)
476			t.Errorf("       got: %#v", got)
477		}
478	}
479}
480