blob: 3c03451202f86543b3f993e7ebb18f215d289fef [file] [log] [blame]
Colin Crossf72ef502015-10-30 11:42:57 -07001// 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 {
Colin Cross12392ca2018-10-02 21:57:47 -070074 // 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 {
Colin Cross80117682015-10-30 15:53:55 -070087 // 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 },
Colin Crossf72ef502015-10-30 11:42:57 -0700106 {
Nan Zhangf5865442017-11-01 14:03:28 -0700107 // 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 {
Colin Crossf72ef502015-10-30 11:42:57 -0700116 // 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 {
Colin Cross83cedbe2015-11-20 17:01:25 -0800155 // 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 }, {
Colin Crossf72ef502015-10-30 11:42:57 -0700175 // 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 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800206 {
207 // Anonymous struct
208 in: &struct {
209 EmbeddedStruct
210 Nested struct{ EmbeddedStruct }
211 }{
212 EmbeddedStruct: EmbeddedStruct{
213 S: "string1",
Nan Zhangf5865442017-11-01 14:03:28 -0700214 I: Int64Ptr(55),
Colin Cross9d1469d2015-11-20 17:03:25 -0800215 },
216 Nested: struct{ EmbeddedStruct }{
217 EmbeddedStruct: EmbeddedStruct{
218 S: "string2",
Nan Zhangf5865442017-11-01 14:03:28 -0700219 I: Int64Ptr(5),
Colin Cross9d1469d2015-11-20 17:03:25 -0800220 },
221 },
222 },
223 out: &struct {
224 EmbeddedStruct
225 Nested struct{ EmbeddedStruct }
226 }{
227 EmbeddedStruct: EmbeddedStruct{
228 S: "string1",
Nan Zhangf5865442017-11-01 14:03:28 -0700229 I: Int64Ptr(55),
Colin Cross9d1469d2015-11-20 17:03:25 -0800230 },
231 Nested: struct{ EmbeddedStruct }{
232 EmbeddedStruct: EmbeddedStruct{
233 S: "string2",
Nan Zhangf5865442017-11-01 14:03:28 -0700234 I: Int64Ptr(5),
Colin Cross9d1469d2015-11-20 17:03:25 -0800235 },
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 },
Colin Crossf72ef502015-10-30 11:42:57 -0700268}
269
Nan Zhangf5865442017-11-01 14:03:28 -0700270type EmbeddedStruct struct {
271 S string
272 I *int64
273}
Colin Cross9d1469d2015-11-20 17:03:25 -0800274type EmbeddedInterface interface{}
275
Colin Crossf72ef502015-10-30 11:42:57 -0700276func TestCloneProperties(t *testing.T) {
277 for _, testCase := range clonePropertiesTestCases {
278 testString := fmt.Sprintf("%s", testCase.in)
279
Colin Cross5d57b2d2020-01-27 16:14:31 -0800280 got := CloneProperties(reflect.ValueOf(testCase.in)).Interface()
Colin Crossf72ef502015-10-30 11:42:57 -0700281
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 {
Colin Cross12392ca2018-10-02 21:57:47 -0700333 // 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 {
Colin Cross80117682015-10-30 15:53:55 -0700344 // 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 {
Nan Zhangf5865442017-11-01 14:03:28 -0700352 // 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 {
Colin Cross80117682015-10-30 15:53:55 -0700360 // Clone pointer to string
361 in: &struct{ S *string }{
362 S: StringPtr("string1"),
363 },
364 out: &struct{ S *string }{},
365 },
Colin Crossf72ef502015-10-30 11:42:57 -0700366 {
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 {
Colin Cross83cedbe2015-11-20 17:01:25 -0800400 // 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 {
Colin Crossf72ef502015-10-30 11:42:57 -0700419 // 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 },
Colin Cross83cedbe2015-11-20 17:01:25 -0800446 {
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 },
Colin Crossf72ef502015-10-30 11:42:57 -0700496}
497
498func TestCloneEmptyProperties(t *testing.T) {
499 for _, testCase := range cloneEmptyPropertiesTestCases {
Colin Cross83cedbe2015-11-20 17:01:25 -0800500 testString := fmt.Sprintf("%#v", testCase.in)
Colin Crossf72ef502015-10-30 11:42:57 -0700501
Colin Cross5d57b2d2020-01-27 16:14:31 -0800502 got := CloneEmptyProperties(reflect.ValueOf(testCase.in)).Interface()
Colin Crossf72ef502015-10-30 11:42:57 -0700503
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 {
Colin Cross83cedbe2015-11-20 17:01:25 -0800515 testString := fmt.Sprintf("%#v", testCase.in)
Colin Crossf72ef502015-10-30 11:42:57 -0700516
Colin Cross5d57b2d2020-01-27 16:14:31 -0800517 got := CloneProperties(reflect.ValueOf(testCase.in)).Interface()
518 ZeroProperties(reflect.ValueOf(got))
Colin Crossf72ef502015-10-30 11:42:57 -0700519
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}