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