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