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