Home | History | Annotate | Download | only in proptools
      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 
     15 package proptools
     16 
     17 import (
     18 	"fmt"
     19 	"reflect"
     20 	"testing"
     21 )
     22 
     23 var 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 
    244 type EmbeddedStruct struct{ S string }
    245 type EmbeddedInterface interface{}
    246 
    247 func 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 
    262 var 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 
    450 func 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 
    465 func 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