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