github.com/vmware/govmomi@v0.43.0/object/option_value_list_test.go (about) 1 /* 2 Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package object_test 18 19 import ( 20 "fmt" 21 "strings" 22 "testing" 23 24 "github.com/stretchr/testify/assert" 25 26 "github.com/vmware/govmomi/object" 27 "github.com/vmware/govmomi/vim25/types" 28 ) 29 30 type nillableOptionValue struct{} 31 32 func (ov nillableOptionValue) GetOptionValue() *types.OptionValue { 33 return nil 34 } 35 36 func TestOptionValueList(t *testing.T) { 37 const ( 38 sza = "a" 39 szb = "b" 40 szc = "c" 41 szd = "d" 42 sze = "e" 43 sz1 = "1" 44 sz2 = "2" 45 sz3 = "3" 46 sz4 = "4" 47 sz5 = "5" 48 i32_1 = int32(1) 49 u64_2 = uint64(2) 50 f32_3 = float32(3) 51 f64_4 = float64(4) 52 b_5 = byte(5) //nolint:revive,stylecheck 53 ) 54 55 var ( 56 psz1 = &[]string{sz1}[0] 57 pu64_2 = &[]uint64{u64_2}[0] 58 pf32_3 = &[]float32{f32_3}[0] 59 pb_5 = &[]byte{b_5}[0] //nolint:revive,stylecheck 60 ) 61 62 t.Run("OptionValueListFromMap", func(t *testing.T) { 63 64 t.Run("a nil map should return nil", func(t *testing.T) { 65 assert.Nil(t, object.OptionValueListFromMap[any](nil)) 66 }) 67 68 t.Run("a map with string values should return OptionValues", func(t *testing.T) { 69 assert.ElementsMatch( 70 t, 71 object.OptionValueListFromMap(map[string]string{ 72 szc: sz3, 73 sza: sz1, 74 szb: sz2, 75 }), 76 []types.BaseOptionValue{ 77 &types.OptionValue{Key: szb, Value: sz2}, 78 &types.OptionValue{Key: sza, Value: sz1}, 79 &types.OptionValue{Key: szc, Value: sz3}, 80 }, 81 ) 82 }) 83 84 t.Run("a map with values of varying numeric types should return OptionValues", func(t *testing.T) { 85 assert.ElementsMatch( 86 t, 87 object.OptionValueListFromMap(map[string]any{ 88 szc: f32_3, 89 sza: i32_1, 90 szb: u64_2, 91 }), 92 []types.BaseOptionValue{ 93 &types.OptionValue{Key: szb, Value: u64_2}, 94 &types.OptionValue{Key: sza, Value: i32_1}, 95 &types.OptionValue{Key: szc, Value: f32_3}, 96 }, 97 ) 98 }) 99 100 t.Run("a map with pointer values should return OptionValues", func(t *testing.T) { 101 assert.ElementsMatch( 102 t, 103 object.OptionValueListFromMap(map[string]any{ 104 szc: pf32_3, 105 sza: psz1, 106 szb: pu64_2, 107 }), 108 []types.BaseOptionValue{ 109 &types.OptionValue{Key: szb, Value: pu64_2}, 110 &types.OptionValue{Key: sza, Value: psz1}, 111 &types.OptionValue{Key: szc, Value: pf32_3}, 112 }, 113 ) 114 }) 115 }) 116 117 t.Run("IsTrueOrFalse", func(t *testing.T) { 118 119 type testCase struct { 120 name string 121 left object.OptionValueList 122 key string 123 ok bool 124 } 125 126 addBoolTestCases := func(b, ok bool) []testCase { 127 return []testCase{ 128 { 129 name: fmt.Sprintf("a key with %v should return %v", b, ok), 130 left: object.OptionValueList{ 131 &types.OptionValue{Key: sza, Value: b}, 132 }, 133 key: sza, 134 ok: ok, 135 }, 136 { 137 name: fmt.Sprintf("a key with %v should return %v", !b, !ok), 138 left: object.OptionValueList{ 139 &types.OptionValue{Key: sza, Value: !b}, 140 }, 141 key: sza, 142 ok: !ok, 143 }, 144 } 145 } 146 147 addNumericalTestCases := func(i int, ok bool) []testCase { 148 return []testCase{ 149 { 150 name: fmt.Sprintf("a key with byte(%v) should return %v", i, ok), 151 left: object.OptionValueList{ 152 &types.OptionValue{Key: sza, Value: byte(i)}, 153 }, 154 key: sza, 155 ok: ok, 156 }, 157 { 158 name: fmt.Sprintf("a key with uint(%v) should return %v", i, ok), 159 left: object.OptionValueList{ 160 &types.OptionValue{Key: sza, Value: uint(i)}, 161 }, 162 key: sza, 163 ok: ok, 164 }, 165 { 166 name: fmt.Sprintf("a key with uint8(%v) should return %v", i, ok), 167 left: object.OptionValueList{ 168 &types.OptionValue{Key: sza, Value: uint8(i)}, 169 }, 170 key: sza, 171 ok: ok, 172 }, 173 { 174 name: fmt.Sprintf("a key with uint16(%v) should return %v", i, ok), 175 left: object.OptionValueList{ 176 &types.OptionValue{Key: sza, Value: uint16(i)}, 177 }, 178 key: sza, 179 ok: ok, 180 }, 181 { 182 name: fmt.Sprintf("a key with uint32(%v) should return %v", i, ok), 183 left: object.OptionValueList{ 184 &types.OptionValue{Key: sza, Value: uint32(i)}, 185 }, 186 key: sza, 187 ok: ok, 188 }, 189 { 190 name: fmt.Sprintf("a key with uint64(%v) should return %v", i, ok), 191 left: object.OptionValueList{ 192 &types.OptionValue{Key: sza, Value: uint64(i)}, 193 }, 194 key: sza, 195 ok: ok, 196 }, 197 198 { 199 name: fmt.Sprintf("a key with int(%v) should return %v", i, ok), 200 left: object.OptionValueList{ 201 &types.OptionValue{Key: sza, Value: int(i)}, 202 }, 203 key: sza, 204 ok: ok, 205 }, 206 { 207 name: fmt.Sprintf("a key with int8(%v) should return %v", i, ok), 208 left: object.OptionValueList{ 209 &types.OptionValue{Key: sza, Value: int8(i)}, 210 }, 211 key: sza, 212 ok: ok, 213 }, 214 { 215 name: fmt.Sprintf("a key with int16(%v) should return %v", i, ok), 216 left: object.OptionValueList{ 217 &types.OptionValue{Key: sza, Value: int16(i)}, 218 }, 219 key: sza, 220 ok: ok, 221 }, 222 { 223 name: fmt.Sprintf("a key with int32(%v) should return %v", i, ok), 224 left: object.OptionValueList{ 225 &types.OptionValue{Key: sza, Value: int32(i)}, 226 }, 227 key: sza, 228 ok: ok, 229 }, 230 { 231 name: fmt.Sprintf("a key with int64(%v) should return %v", i, ok), 232 left: object.OptionValueList{ 233 &types.OptionValue{Key: sza, Value: int64(i)}, 234 }, 235 key: sza, 236 ok: ok, 237 }, 238 239 { 240 name: fmt.Sprintf("a key with float32(%v) should return %v", i, ok), 241 left: object.OptionValueList{ 242 &types.OptionValue{Key: sza, Value: float32(i)}, 243 }, 244 key: sza, 245 ok: ok, 246 }, 247 { 248 name: fmt.Sprintf("a key with float64(%v) should return %v", i, ok), 249 left: object.OptionValueList{ 250 &types.OptionValue{Key: sza, Value: float64(i)}, 251 }, 252 key: sza, 253 ok: ok, 254 }, 255 } 256 } 257 258 addTestCasesForPermutedString := func(s string, ok bool) []testCase { 259 var testCases []testCase 260 for _, s := range permuteByCase(s) { 261 testCases = append(testCases, testCase{ 262 name: fmt.Sprintf("a key with %q should return %v", s, ok), 263 left: object.OptionValueList{ 264 &types.OptionValue{Key: sza, Value: s}, 265 }, 266 key: sza, 267 ok: ok, 268 }) 269 } 270 return testCases 271 } 272 273 addTestCasesForPermutedStrings := func(ok bool, args ...string) []testCase { 274 var testCases []testCase 275 for i := range args { 276 testCases = append(testCases, addTestCasesForPermutedString(args[i], ok)...) 277 } 278 return testCases 279 } 280 281 baseTestCases := []testCase{ 282 { 283 name: "a nil receiver should not panic and return false", 284 left: nil, 285 key: "", 286 ok: false, 287 }, 288 { 289 name: "a non-existent key should return false", 290 left: object.OptionValueList{}, 291 key: "", 292 ok: false, 293 }, 294 } 295 296 runTests := func(t *testing.T, expected bool) { 297 testCases := append([]testCase{}, baseTestCases...) 298 299 for i := range baseTestCases { 300 tc := testCases[i] 301 t.Run(tc.name, func(t *testing.T) { 302 var ok bool 303 if expected { 304 assert.NotPanics(t, func() { ok = tc.left.IsTrue(tc.key) }) 305 assert.Equal(t, tc.ok, ok) 306 } else { 307 assert.NotPanics(t, func() { ok = tc.left.IsFalse(tc.key) }) 308 assert.Equal(t, tc.ok, ok) 309 } 310 }) 311 } 312 313 testCases = append([]testCase{}, addBoolTestCases(true, expected)...) 314 testCases = append(testCases, addNumericalTestCases(0, !expected)...) 315 testCases = append(testCases, addNumericalTestCases(1, expected)...) 316 testCases = append(testCases, addTestCasesForPermutedStrings(expected, "", "1", "on", "t", "true", "y", "yes")...) 317 testCases = append(testCases, addTestCasesForPermutedStrings(!expected, "0", "f", "false", "n", "no", "off")...) 318 319 for i := range testCases { 320 tc := testCases[i] 321 t.Run(tc.name, func(t *testing.T) { 322 var ok bool 323 if expected { 324 assert.NotPanics(t, func() { ok = tc.left.IsTrue(tc.key) }) 325 assert.Equal(t, tc.ok, ok) 326 assert.NotPanics(t, func() { ok = tc.left.IsFalse(tc.key) }) 327 assert.Equal(t, !tc.ok, ok) 328 } else { 329 assert.NotPanics(t, func() { ok = tc.left.IsTrue(tc.key) }) 330 assert.Equal(t, !tc.ok, ok) 331 assert.NotPanics(t, func() { ok = tc.left.IsFalse(tc.key) }) 332 assert.Equal(t, tc.ok, ok) 333 } 334 335 }) 336 } 337 } 338 339 t.Run("IsTrue", func(t *testing.T) { runTests(t, true) }) 340 t.Run("IsFalse", func(t *testing.T) { runTests(t, false) }) 341 342 }) 343 344 t.Run("Get", func(t *testing.T) { 345 testCases := []struct { 346 name string 347 left object.OptionValueList 348 key string 349 out any 350 ok bool 351 }{ 352 { 353 name: "a nil receiver should not panic and return nil, false", 354 left: nil, 355 key: "", 356 out: nil, 357 ok: false, 358 }, 359 { 360 name: "a non-existent key should return nil, false", 361 left: object.OptionValueList{}, 362 key: "", 363 out: nil, 364 ok: false, 365 }, 366 { 367 name: "an existing key should return its value, true", 368 left: object.OptionValueList{ 369 &types.OptionValue{Key: sza, Value: sz1}, 370 }, 371 key: sza, 372 out: sz1, 373 ok: true, 374 }, 375 { 376 name: "an existing key should return its value, true when data includes a nillable types.BaseOptionValue", 377 left: object.OptionValueList{ 378 nillableOptionValue{}, 379 &types.OptionValue{Key: sza, Value: sz1}, 380 }, 381 key: sza, 382 out: sz1, 383 ok: true, 384 }, 385 } 386 387 for i := range testCases { 388 tc := testCases[i] 389 t.Run(tc.name, func(t *testing.T) { 390 var ( 391 out any 392 ok bool 393 ) 394 assert.NotPanics(t, func() { out, ok = tc.left.Get(tc.key) }) 395 assert.Equal(t, tc.out, out) 396 assert.Equal(t, tc.ok, ok) 397 }) 398 } 399 }) 400 401 t.Run("GetString", func(t *testing.T) { 402 testCases := []struct { 403 name string 404 left object.OptionValueList 405 key string 406 out string 407 ok bool 408 }{ 409 { 410 name: "a nil receiver should not panic and return \"\", false", 411 left: nil, 412 key: "", 413 out: "", 414 ok: false, 415 }, 416 { 417 name: "a non-existent key should return \"\", false", 418 left: object.OptionValueList{}, 419 key: "", 420 out: "", 421 ok: false, 422 }, 423 { 424 name: "an existing key for a string value should return its string value, true", 425 left: object.OptionValueList{ 426 &types.OptionValue{Key: sza, Value: sz1}, 427 }, 428 key: sza, 429 out: sz1, 430 ok: true, 431 }, 432 { 433 name: "an existing key for a *string value that is not nil should return its string value, true", 434 left: object.OptionValueList{ 435 &types.OptionValue{Key: sza, Value: psz1}, 436 }, 437 key: sza, 438 out: sz1, 439 ok: true, 440 }, 441 { 442 name: "an existing key for a *string value that is nil should return \"\", true", 443 left: object.OptionValueList{ 444 &types.OptionValue{Key: sza, Value: (*string)(nil)}, 445 }, 446 key: sza, 447 out: "", 448 ok: true, 449 }, 450 { 451 name: "an existing key for an int32 value should return its string value, true", 452 left: object.OptionValueList{ 453 &types.OptionValue{Key: sza, Value: i32_1}, 454 }, 455 key: sza, 456 out: sz1, 457 ok: true, 458 }, 459 { 460 name: "an existing key for a *uint64 value that is not nil should return its string value, true", 461 left: object.OptionValueList{ 462 &types.OptionValue{Key: sza, Value: pu64_2}, 463 }, 464 key: sza, 465 out: sz2, 466 ok: true, 467 }, 468 { 469 name: "an existing key for a *uint64 value that is nil should return \"\", true", 470 left: object.OptionValueList{ 471 &types.OptionValue{Key: sza, Value: (*uint64)(nil)}, 472 }, 473 key: sza, 474 out: "", 475 ok: true, 476 }, 477 { 478 name: "an existing key for a string value should return its string value, true when data includes a nillable types.BaseOptionValue", 479 left: object.OptionValueList{ 480 nillableOptionValue{}, 481 &types.OptionValue{Key: sza, Value: sz1}, 482 }, 483 key: sza, 484 out: sz1, 485 ok: true, 486 }, 487 } 488 489 for i := range testCases { 490 tc := testCases[i] 491 t.Run(tc.name, func(t *testing.T) { 492 var ( 493 out string 494 ok bool 495 ) 496 assert.NotPanics(t, func() { out, ok = tc.left.GetString(tc.key) }) 497 assert.Equal(t, tc.out, out) 498 assert.Equal(t, tc.ok, ok) 499 }) 500 } 501 }) 502 503 t.Run("Map", func(t *testing.T) { 504 testCases := []struct { 505 name string 506 left object.OptionValueList 507 out map[string]any 508 }{ 509 { 510 name: "a nil receiver should not panic and return nil", 511 left: nil, 512 out: nil, 513 }, 514 { 515 name: "data with homogeneous values should return a map", 516 left: object.OptionValueList{ 517 &types.OptionValue{Key: sza, Value: sz1}, 518 }, 519 out: map[string]any{ 520 sza: sz1, 521 }, 522 }, 523 { 524 name: "data with heterogeneous values should return a map", 525 left: object.OptionValueList{ 526 &types.OptionValue{Key: sza, Value: sz1}, 527 &types.OptionValue{Key: szb, Value: u64_2}, 528 &types.OptionValue{Key: szc, Value: pf32_3}, 529 }, 530 out: map[string]any{ 531 sza: sz1, 532 szb: u64_2, 533 szc: pf32_3, 534 }, 535 }, 536 { 537 name: "data with just a nillable types.BaseOptionValue should return nil", 538 left: object.OptionValueList{ 539 nillableOptionValue{}, 540 }, 541 out: nil, 542 }, 543 } 544 545 for i := range testCases { 546 tc := testCases[i] 547 t.Run(tc.name, func(t *testing.T) { 548 var out map[string]any 549 assert.NotPanics(t, func() { out = tc.left.Map() }) 550 assert.Equal(t, tc.out, out) 551 }) 552 } 553 }) 554 555 t.Run("StringMap", func(t *testing.T) { 556 testCases := []struct { 557 name string 558 left object.OptionValueList 559 out map[string]string 560 }{ 561 { 562 name: "a nil receiver should not panic and return nil", 563 left: nil, 564 out: nil, 565 }, 566 { 567 name: "data with homogeneous values should return a map", 568 left: object.OptionValueList{ 569 &types.OptionValue{Key: sza, Value: sz1}, 570 }, 571 out: map[string]string{ 572 sza: sz1, 573 }, 574 }, 575 { 576 name: "data with heterogeneous values should return a map", 577 left: object.OptionValueList{ 578 &types.OptionValue{Key: sza, Value: sz1}, 579 &types.OptionValue{Key: szb, Value: u64_2}, 580 &types.OptionValue{Key: szc, Value: pf32_3}, 581 }, 582 out: map[string]string{ 583 sza: sz1, 584 szb: sz2, 585 szc: sz3, 586 }, 587 }, 588 { 589 name: "data with just a nillable types.BaseOptionValue should return nil", 590 left: object.OptionValueList{ 591 nillableOptionValue{}, 592 }, 593 out: nil, 594 }, 595 } 596 597 for i := range testCases { 598 tc := testCases[i] 599 t.Run(tc.name, func(t *testing.T) { 600 var out map[string]string 601 assert.NotPanics(t, func() { out = tc.left.StringMap() }) 602 assert.Equal(t, tc.out, out) 603 }) 604 } 605 }) 606 607 t.Run("Additions", func(t *testing.T) { 608 testCases := []struct { 609 name string 610 left object.OptionValueList 611 right object.OptionValueList 612 out object.OptionValueList 613 }{ 614 { 615 name: "a nil receiver and nil input should not panic and return nil", 616 left: nil, 617 right: nil, 618 out: nil, 619 }, 620 { 621 name: "a nil receiver and non-nil input should not panic and return the diff", 622 left: nil, 623 right: object.OptionValueList{ 624 &types.OptionValue{Key: szb, Value: ""}, 625 &types.OptionValue{Key: szd, Value: f64_4}, 626 &types.OptionValue{Key: sze, Value: pb_5}, 627 }, 628 out: object.OptionValueList{ 629 &types.OptionValue{Key: szb, Value: ""}, 630 &types.OptionValue{Key: szd, Value: f64_4}, 631 &types.OptionValue{Key: sze, Value: pb_5}, 632 }, 633 }, 634 { 635 name: "a non-nil receiver and nil input should return nil", 636 left: object.OptionValueList{ 637 &types.OptionValue{Key: sza, Value: sz1}, 638 &types.OptionValue{Key: szb, Value: sz2}, 639 &types.OptionValue{Key: szc, Value: sz3}, 640 }, 641 right: nil, 642 out: nil, 643 }, 644 { 645 name: "a non-nil receiver and non-nil input should return the diff", 646 left: object.OptionValueList{ 647 &types.OptionValue{Key: sza, Value: sz1}, 648 &types.OptionValue{Key: szb, Value: sz2}, 649 &types.OptionValue{Key: szc, Value: sz3}, 650 }, 651 right: object.OptionValueList{ 652 &types.OptionValue{Key: szb, Value: ""}, 653 &types.OptionValue{Key: szd, Value: f64_4}, 654 &types.OptionValue{Key: sze, Value: pb_5}, 655 }, 656 out: object.OptionValueList{ 657 &types.OptionValue{Key: szd, Value: f64_4}, 658 &types.OptionValue{Key: sze, Value: pb_5}, 659 }, 660 }, 661 } 662 663 for i := range testCases { 664 tc := testCases[i] 665 t.Run(tc.name, func(t *testing.T) { 666 var out object.OptionValueList 667 assert.NotPanics(t, func() { out = tc.left.Additions(tc.right...) }) 668 assert.Equal(t, tc.out, out) 669 }) 670 } 671 }) 672 673 t.Run("Diff", func(t *testing.T) { 674 testCases := []struct { 675 name string 676 left object.OptionValueList 677 right object.OptionValueList 678 out object.OptionValueList 679 }{ 680 { 681 name: "a nil receiver and nil input should not panic and return nil", 682 left: nil, 683 right: nil, 684 out: nil, 685 }, 686 { 687 name: "a nil receiver and non-nil input should not panic and return the diff", 688 left: nil, 689 right: object.OptionValueList{ 690 &types.OptionValue{Key: szb, Value: ""}, 691 &types.OptionValue{Key: szd, Value: f64_4}, 692 &types.OptionValue{Key: sze, Value: pb_5}, 693 }, 694 out: object.OptionValueList{ 695 &types.OptionValue{Key: szb, Value: ""}, 696 &types.OptionValue{Key: szd, Value: f64_4}, 697 &types.OptionValue{Key: sze, Value: pb_5}, 698 }, 699 }, 700 { 701 name: "a non-nil receiver and nil input should return nil", 702 left: object.OptionValueList{ 703 &types.OptionValue{Key: sza, Value: sz1}, 704 &types.OptionValue{Key: szb, Value: sz2}, 705 &types.OptionValue{Key: szc, Value: sz3}, 706 }, 707 right: nil, 708 out: nil, 709 }, 710 { 711 name: "a non-nil receiver and non-nil input should return the diff", 712 left: object.OptionValueList{ 713 &types.OptionValue{Key: sza, Value: sz1}, 714 &types.OptionValue{Key: szb, Value: sz2}, 715 &types.OptionValue{Key: szc, Value: sz3}, 716 }, 717 right: object.OptionValueList{ 718 &types.OptionValue{Key: szb, Value: ""}, 719 &types.OptionValue{Key: szd, Value: f64_4}, 720 &types.OptionValue{Key: sze, Value: pb_5}, 721 }, 722 out: object.OptionValueList{ 723 &types.OptionValue{Key: szb, Value: ""}, 724 &types.OptionValue{Key: szd, Value: f64_4}, 725 &types.OptionValue{Key: sze, Value: pb_5}, 726 }, 727 }, 728 } 729 730 for i := range testCases { 731 tc := testCases[i] 732 t.Run(tc.name, func(t *testing.T) { 733 var out object.OptionValueList 734 assert.NotPanics(t, func() { out = tc.left.Diff(tc.right...) }) 735 assert.Equal(t, tc.out, out) 736 }) 737 } 738 }) 739 740 t.Run("Join", func(t *testing.T) { 741 testCases := []struct { 742 name string 743 left object.OptionValueList 744 right object.OptionValueList 745 out object.OptionValueList 746 }{ 747 { 748 name: "a nil receiver and nil input should not panic and return nil", 749 left: nil, 750 right: nil, 751 out: nil, 752 }, 753 { 754 name: "a nil receiver and non-nil input should not panic and return the joined data", 755 left: nil, 756 right: object.OptionValueList{ 757 &types.OptionValue{Key: szb, Value: ""}, 758 &types.OptionValue{Key: szd, Value: f64_4}, 759 &types.OptionValue{Key: sze, Value: pb_5}, 760 }, 761 out: object.OptionValueList{ 762 &types.OptionValue{Key: szb, Value: ""}, 763 &types.OptionValue{Key: szd, Value: f64_4}, 764 &types.OptionValue{Key: sze, Value: pb_5}, 765 }, 766 }, 767 { 768 name: "a non-nil receiver and nil input should return the joined data", 769 left: object.OptionValueList{ 770 &types.OptionValue{Key: sza, Value: sz1}, 771 &types.OptionValue{Key: szb, Value: sz2}, 772 &types.OptionValue{Key: szc, Value: sz3}, 773 }, 774 right: nil, 775 out: object.OptionValueList{ 776 &types.OptionValue{Key: sza, Value: sz1}, 777 &types.OptionValue{Key: szb, Value: sz2}, 778 &types.OptionValue{Key: szc, Value: sz3}, 779 }, 780 }, 781 { 782 name: "a non-nil receiver and non-nil input should return the joined data", 783 left: object.OptionValueList{ 784 &types.OptionValue{Key: sza, Value: sz1}, 785 &types.OptionValue{Key: szb, Value: sz2}, 786 &types.OptionValue{Key: szc, Value: sz3}, 787 }, 788 right: object.OptionValueList{ 789 &types.OptionValue{Key: szb, Value: ""}, 790 &types.OptionValue{Key: szd, Value: f64_4}, 791 &types.OptionValue{Key: sze, Value: pb_5}, 792 }, 793 out: object.OptionValueList{ 794 &types.OptionValue{Key: sza, Value: sz1}, 795 &types.OptionValue{Key: szb, Value: sz2}, 796 &types.OptionValue{Key: szc, Value: sz3}, 797 &types.OptionValue{Key: szd, Value: f64_4}, 798 &types.OptionValue{Key: sze, Value: pb_5}, 799 }, 800 }, 801 { 802 name: "a non-nil receiver and non-nil input, flipping left and right, should return the joined data", 803 left: object.OptionValueList{ 804 &types.OptionValue{Key: szb, Value: ""}, 805 &types.OptionValue{Key: szd, Value: f64_4}, 806 &types.OptionValue{Key: sze, Value: pb_5}, 807 }, 808 right: object.OptionValueList{ 809 &types.OptionValue{Key: sza, Value: sz1}, 810 &types.OptionValue{Key: szb, Value: sz2}, 811 &types.OptionValue{Key: szc, Value: sz3}, 812 }, 813 out: object.OptionValueList{ 814 &types.OptionValue{Key: szb, Value: ""}, 815 &types.OptionValue{Key: szd, Value: f64_4}, 816 &types.OptionValue{Key: sze, Value: pb_5}, 817 &types.OptionValue{Key: sza, Value: sz1}, 818 &types.OptionValue{Key: szc, Value: sz3}, 819 }, 820 }, 821 } 822 823 for i := range testCases { 824 tc := testCases[i] 825 t.Run(tc.name, func(t *testing.T) { 826 var out object.OptionValueList 827 assert.NotPanics(t, func() { out = tc.left.Join(tc.right...) }) 828 assert.Equal(t, tc.out, out) 829 }) 830 } 831 }) 832 } 833 834 func permuteByCase(s string) []string { 835 if len(s) == 0 { 836 return []string{s} 837 } 838 839 if len(s) == 1 { 840 lc := strings.ToLower(s) 841 uc := strings.ToUpper(s) 842 if lc == uc { 843 return []string{s} 844 } 845 return []string{lc, uc} 846 } 847 848 var p []string 849 for _, i := range permuteByCase(s[0:1]) { 850 for _, j := range permuteByCase(s[1:]) { 851 p = append(p, fmt.Sprintf("%s%s", i, j)) 852 } 853 } 854 855 return p 856 }