1// Copyright 2014 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 "bytes" 19 "reflect" 20 21 "testing" 22 23 "github.com/google/blueprint/parser" 24) 25 26var validUnpackTestCases = []struct { 27 name string 28 input string 29 output []interface{} 30 empty []interface{} 31 errs []error 32}{ 33 { 34 name: "blank and unset", 35 input: ` 36 m { 37 s: "abc", 38 blank: "", 39 } 40 `, 41 output: []interface{}{ 42 &struct { 43 S *string 44 Blank *string 45 Unset *string 46 }{ 47 S: StringPtr("abc"), 48 Blank: StringPtr(""), 49 Unset: nil, 50 }, 51 }, 52 }, 53 54 { 55 name: "string", 56 input: ` 57 m { 58 s: "abc", 59 } 60 `, 61 output: []interface{}{ 62 &struct { 63 S string 64 }{ 65 S: "abc", 66 }, 67 }, 68 }, 69 70 { 71 name: "bool", 72 input: ` 73 m { 74 isGood: true, 75 } 76 `, 77 output: []interface{}{ 78 &struct { 79 IsGood bool 80 }{ 81 IsGood: true, 82 }, 83 }, 84 }, 85 86 { 87 name: "boolptr", 88 input: ` 89 m { 90 isGood: true, 91 isBad: false, 92 } 93 `, 94 output: []interface{}{ 95 &struct { 96 IsGood *bool 97 IsBad *bool 98 IsUgly *bool 99 }{ 100 IsGood: BoolPtr(true), 101 IsBad: BoolPtr(false), 102 IsUgly: nil, 103 }, 104 }, 105 }, 106 107 { 108 name: "slice", 109 input: ` 110 m { 111 stuff: ["asdf", "jkl;", "qwert", 112 "uiop", "bnm,"], 113 empty: [] 114 } 115 `, 116 output: []interface{}{ 117 &struct { 118 Stuff []string 119 Empty []string 120 Nil []string 121 NonString []struct{ S string } `blueprint:"mutated"` 122 }{ 123 Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"}, 124 Empty: []string{}, 125 Nil: nil, 126 NonString: nil, 127 }, 128 }, 129 }, 130 131 { 132 name: "double nested", 133 input: ` 134 m { 135 nested: { 136 nested: { 137 s: "abc", 138 }, 139 }, 140 } 141 `, 142 output: []interface{}{ 143 &struct { 144 Nested struct { 145 Nested struct { 146 S string 147 } 148 } 149 }{ 150 Nested: struct{ Nested struct{ S string } }{ 151 Nested: struct{ S string }{ 152 S: "abc", 153 }, 154 }, 155 }, 156 }, 157 }, 158 159 { 160 name: "nested", 161 input: ` 162 m { 163 nested: { 164 s: "abc", 165 } 166 } 167 `, 168 output: []interface{}{ 169 &struct { 170 Nested struct { 171 S string 172 } 173 }{ 174 Nested: struct{ S string }{ 175 S: "abc", 176 }, 177 }, 178 }, 179 }, 180 181 { 182 name: "nested interface", 183 input: ` 184 m { 185 nested: { 186 s: "def", 187 } 188 } 189 `, 190 output: []interface{}{ 191 &struct { 192 Nested interface{} 193 }{ 194 Nested: &struct{ S string }{ 195 S: "def", 196 }, 197 }, 198 }, 199 }, 200 201 { 202 name: "mixed", 203 input: ` 204 m { 205 nested: { 206 foo: "abc", 207 }, 208 bar: false, 209 baz: ["def", "ghi"], 210 } 211 `, 212 output: []interface{}{ 213 &struct { 214 Nested struct { 215 Foo string 216 } 217 Bar bool 218 Baz []string 219 }{ 220 Nested: struct{ Foo string }{ 221 Foo: "abc", 222 }, 223 Bar: false, 224 Baz: []string{"def", "ghi"}, 225 }, 226 }, 227 }, 228 229 { 230 name: "filter", 231 input: ` 232 m { 233 nested: { 234 foo: "abc", 235 }, 236 bar: false, 237 baz: ["def", "ghi"], 238 } 239 `, 240 output: []interface{}{ 241 &struct { 242 Nested struct { 243 Foo string `allowNested:"true"` 244 } `blueprint:"filter(allowNested:\"true\")"` 245 Bar bool 246 Baz []string 247 }{ 248 Nested: struct { 249 Foo string `allowNested:"true"` 250 }{ 251 Foo: "abc", 252 }, 253 Bar: false, 254 Baz: []string{"def", "ghi"}, 255 }, 256 }, 257 }, 258 259 // List of maps 260 { 261 name: "list of structs", 262 input: ` 263 m { 264 mapslist: [ 265 { 266 foo: "abc", 267 bar: true, 268 }, 269 { 270 foo: "def", 271 bar: false, 272 } 273 ], 274 } 275 `, 276 output: []interface{}{ 277 &struct { 278 Mapslist []struct { 279 Foo string 280 Bar bool 281 } 282 }{ 283 Mapslist: []struct { 284 Foo string 285 Bar bool 286 }{ 287 {Foo: "abc", Bar: true}, 288 {Foo: "def", Bar: false}, 289 }, 290 }, 291 }, 292 }, 293 294 // List of pointers to structs 295 { 296 name: "list of pointers to structs", 297 input: ` 298 m { 299 mapslist: [ 300 { 301 foo: "abc", 302 bar: true, 303 }, 304 { 305 foo: "def", 306 bar: false, 307 } 308 ], 309 } 310 `, 311 output: []interface{}{ 312 &struct { 313 Mapslist []*struct { 314 Foo string 315 Bar bool 316 } 317 }{ 318 Mapslist: []*struct { 319 Foo string 320 Bar bool 321 }{ 322 {Foo: "abc", Bar: true}, 323 {Foo: "def", Bar: false}, 324 }, 325 }, 326 }, 327 }, 328 329 // List of lists 330 { 331 name: "list of lists", 332 input: ` 333 m { 334 listoflists: [ 335 ["abc",], 336 ["def",], 337 ], 338 } 339 `, 340 output: []interface{}{ 341 &struct { 342 Listoflists [][]string 343 }{ 344 Listoflists: [][]string{ 345 []string{"abc"}, 346 []string{"def"}, 347 }, 348 }, 349 }, 350 }, 351 352 // Multilevel 353 { 354 name: "multilevel", 355 input: ` 356 m { 357 name: "mymodule", 358 flag: true, 359 settings: ["foo1", "foo2", "foo3",], 360 perarch: { 361 arm: "32", 362 arm64: "64", 363 }, 364 configvars: [ 365 { var: "var1", values: ["1.1", "1.2", ], }, 366 { var: "var2", values: ["2.1", ], }, 367 ], 368 } 369 `, 370 output: []interface{}{ 371 &struct { 372 Name string 373 Flag bool 374 Settings []string 375 Perarch *struct { 376 Arm string 377 Arm64 string 378 } 379 Configvars []struct { 380 Var string 381 Values []string 382 } 383 }{ 384 Name: "mymodule", 385 Flag: true, 386 Settings: []string{"foo1", "foo2", "foo3"}, 387 Perarch: &struct { 388 Arm string 389 Arm64 string 390 }{Arm: "32", Arm64: "64"}, 391 Configvars: []struct { 392 Var string 393 Values []string 394 }{ 395 {Var: "var1", Values: []string{"1.1", "1.2"}}, 396 {Var: "var2", Values: []string{"2.1"}}, 397 }, 398 }, 399 }, 400 }, 401 // Anonymous struct 402 { 403 name: "embedded struct", 404 input: ` 405 m { 406 s: "abc", 407 nested: { 408 s: "def", 409 }, 410 } 411 `, 412 output: []interface{}{ 413 &struct { 414 EmbeddedStruct 415 Nested struct { 416 EmbeddedStruct 417 } 418 }{ 419 EmbeddedStruct: EmbeddedStruct{ 420 S: "abc", 421 }, 422 Nested: struct { 423 EmbeddedStruct 424 }{ 425 EmbeddedStruct: EmbeddedStruct{ 426 S: "def", 427 }, 428 }, 429 }, 430 }, 431 }, 432 433 // Anonymous interface 434 { 435 name: "embedded interface", 436 input: ` 437 m { 438 s: "abc", 439 nested: { 440 s: "def", 441 }, 442 } 443 `, 444 output: []interface{}{ 445 &struct { 446 EmbeddedInterface 447 Nested struct { 448 EmbeddedInterface 449 } 450 }{ 451 EmbeddedInterface: &struct{ S string }{ 452 S: "abc", 453 }, 454 Nested: struct { 455 EmbeddedInterface 456 }{ 457 EmbeddedInterface: &struct{ S string }{ 458 S: "def", 459 }, 460 }, 461 }, 462 }, 463 }, 464 465 // Anonymous struct with name collision 466 { 467 name: "embedded name collision", 468 input: ` 469 m { 470 s: "abc", 471 nested: { 472 s: "def", 473 }, 474 } 475 `, 476 output: []interface{}{ 477 &struct { 478 S string 479 EmbeddedStruct 480 Nested struct { 481 S string 482 EmbeddedStruct 483 } 484 }{ 485 S: "abc", 486 EmbeddedStruct: EmbeddedStruct{ 487 S: "abc", 488 }, 489 Nested: struct { 490 S string 491 EmbeddedStruct 492 }{ 493 S: "def", 494 EmbeddedStruct: EmbeddedStruct{ 495 S: "def", 496 }, 497 }, 498 }, 499 }, 500 }, 501 502 // Anonymous interface with name collision 503 { 504 name: "embeded interface name collision", 505 input: ` 506 m { 507 s: "abc", 508 nested: { 509 s: "def", 510 }, 511 } 512 `, 513 output: []interface{}{ 514 &struct { 515 S string 516 EmbeddedInterface 517 Nested struct { 518 S string 519 EmbeddedInterface 520 } 521 }{ 522 S: "abc", 523 EmbeddedInterface: &struct{ S string }{ 524 S: "abc", 525 }, 526 Nested: struct { 527 S string 528 EmbeddedInterface 529 }{ 530 S: "def", 531 EmbeddedInterface: &struct{ S string }{ 532 S: "def", 533 }, 534 }, 535 }, 536 }, 537 }, 538 539 // Variables 540 { 541 name: "variables", 542 input: ` 543 list = ["abc"] 544 string = "def" 545 list_with_variable = [string] 546 struct_value = { name: "foo" } 547 m { 548 s: string, 549 list: list, 550 list2: list_with_variable, 551 structattr: struct_value, 552 } 553 `, 554 output: []interface{}{ 555 &struct { 556 S string 557 List []string 558 List2 []string 559 Structattr struct { 560 Name string 561 } 562 }{ 563 S: "def", 564 List: []string{"abc"}, 565 List2: []string{"def"}, 566 Structattr: struct { 567 Name string 568 }{ 569 Name: "foo", 570 }, 571 }, 572 }, 573 }, 574 575 // Multiple property structs 576 { 577 name: "multiple", 578 input: ` 579 m { 580 nested: { 581 s: "abc", 582 } 583 } 584 `, 585 output: []interface{}{ 586 &struct { 587 Nested struct { 588 S string 589 } 590 }{ 591 Nested: struct{ S string }{ 592 S: "abc", 593 }, 594 }, 595 &struct { 596 Nested struct { 597 S string 598 } 599 }{ 600 Nested: struct{ S string }{ 601 S: "abc", 602 }, 603 }, 604 &struct { 605 }{}, 606 }, 607 }, 608 609 // Nil pointer to struct 610 { 611 name: "nil struct pointer", 612 input: ` 613 m { 614 nested: { 615 s: "abc", 616 } 617 } 618 `, 619 output: []interface{}{ 620 &struct { 621 Nested *struct { 622 S string 623 } 624 }{ 625 Nested: &struct{ S string }{ 626 S: "abc", 627 }, 628 }, 629 }, 630 empty: []interface{}{ 631 &struct { 632 Nested *struct { 633 S string 634 } 635 }{}, 636 }, 637 }, 638 639 // Interface containing nil pointer to struct 640 { 641 name: "interface nil struct pointer", 642 input: ` 643 m { 644 nested: { 645 s: "abc", 646 } 647 } 648 `, 649 output: []interface{}{ 650 &struct { 651 Nested interface{} 652 }{ 653 Nested: &EmbeddedStruct{ 654 S: "abc", 655 }, 656 }, 657 }, 658 empty: []interface{}{ 659 &struct { 660 Nested interface{} 661 }{ 662 Nested: (*EmbeddedStruct)(nil), 663 }, 664 }, 665 }, 666 667 // Factory set properties 668 { 669 name: "factory properties", 670 input: ` 671 m { 672 string: "abc", 673 string_ptr: "abc", 674 bool: false, 675 bool_ptr: false, 676 list: ["a", "b", "c"], 677 } 678 `, 679 output: []interface{}{ 680 &struct { 681 String string 682 String_ptr *string 683 Bool bool 684 Bool_ptr *bool 685 List []string 686 }{ 687 String: "012abc", 688 String_ptr: StringPtr("abc"), 689 Bool: true, 690 Bool_ptr: BoolPtr(false), 691 List: []string{"0", "1", "2", "a", "b", "c"}, 692 }, 693 }, 694 empty: []interface{}{ 695 &struct { 696 String string 697 String_ptr *string 698 Bool bool 699 Bool_ptr *bool 700 List []string 701 }{ 702 String: "012", 703 String_ptr: StringPtr("012"), 704 Bool: true, 705 Bool_ptr: BoolPtr(true), 706 List: []string{"0", "1", "2"}, 707 }, 708 }, 709 }, 710 // Captitalized property 711 { 712 input: ` 713 m { 714 CAPITALIZED: "foo", 715 } 716 `, 717 output: []interface{}{ 718 &struct { 719 CAPITALIZED string 720 }{ 721 CAPITALIZED: "foo", 722 }, 723 }, 724 }, 725} 726 727func TestUnpackProperties(t *testing.T) { 728 for _, testCase := range validUnpackTestCases { 729 t.Run(testCase.name, func(t *testing.T) { 730 r := bytes.NewBufferString(testCase.input) 731 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil)) 732 if len(errs) != 0 { 733 t.Errorf("test case: %s", testCase.input) 734 t.Errorf("unexpected parse errors:") 735 for _, err := range errs { 736 t.Errorf(" %s", err) 737 } 738 t.FailNow() 739 } 740 741 for _, def := range file.Defs { 742 module, ok := def.(*parser.Module) 743 if !ok { 744 continue 745 } 746 747 var output []interface{} 748 if len(testCase.empty) > 0 { 749 for _, p := range testCase.empty { 750 output = append(output, CloneProperties(reflect.ValueOf(p)).Interface()) 751 } 752 } else { 753 for _, p := range testCase.output { 754 output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface()) 755 } 756 } 757 758 _, errs = UnpackProperties(module.Properties, output...) 759 if len(errs) != 0 && len(testCase.errs) == 0 { 760 t.Errorf("test case: %s", testCase.input) 761 t.Errorf("unexpected unpack errors:") 762 for _, err := range errs { 763 t.Errorf(" %s", err) 764 } 765 t.FailNow() 766 } else if !reflect.DeepEqual(errs, testCase.errs) { 767 t.Errorf("test case: %s", testCase.input) 768 t.Errorf("incorrect errors:") 769 t.Errorf(" expected: %+v", testCase.errs) 770 t.Errorf(" got: %+v", errs) 771 } 772 773 if len(output) != len(testCase.output) { 774 t.Fatalf("incorrect number of property structs, expected %d got %d", 775 len(testCase.output), len(output)) 776 } 777 778 for i := range output { 779 got := reflect.ValueOf(output[i]).Interface() 780 if !reflect.DeepEqual(got, testCase.output[i]) { 781 t.Errorf("test case: %s", testCase.input) 782 t.Errorf("incorrect output:") 783 t.Errorf(" expected: %+v", testCase.output[i]) 784 t.Errorf(" got: %+v", got) 785 } 786 } 787 } 788 }) 789 } 790} 791 792func TestUnpackErrors(t *testing.T) { 793 testCases := []struct { 794 name string 795 input string 796 output []interface{} 797 errors []string 798 }{ 799 { 800 name: "missing", 801 input: ` 802 m { 803 missing: true, 804 } 805 `, 806 output: []interface{}{}, 807 errors: []string{`<input>:3:13: unrecognized property "missing"`}, 808 }, 809 { 810 name: "missing nested", 811 input: ` 812 m { 813 nested: { 814 missing: true, 815 }, 816 } 817 `, 818 output: []interface{}{ 819 &struct { 820 Nested struct{} 821 }{}, 822 }, 823 errors: []string{`<input>:4:14: unrecognized property "nested.missing"`}, 824 }, 825 { 826 name: "mutated", 827 input: ` 828 m { 829 mutated: true, 830 } 831 `, 832 output: []interface{}{ 833 &struct { 834 Mutated bool `blueprint:"mutated"` 835 }{}, 836 }, 837 errors: []string{`<input>:3:13: mutated field mutated cannot be set in a Blueprint file`}, 838 }, 839 { 840 name: "nested mutated", 841 input: ` 842 m { 843 nested: { 844 mutated: true, 845 }, 846 } 847 `, 848 output: []interface{}{ 849 &struct { 850 Nested struct { 851 Mutated bool `blueprint:"mutated"` 852 } 853 }{}, 854 }, 855 errors: []string{`<input>:4:14: mutated field nested.mutated cannot be set in a Blueprint file`}, 856 }, 857 { 858 name: "duplicate", 859 input: ` 860 m { 861 exists: true, 862 exists: true, 863 } 864 `, 865 output: []interface{}{ 866 &struct { 867 Exists bool 868 }{}, 869 }, 870 errors: []string{ 871 `<input>:4:12: property "exists" already defined`, 872 `<input>:3:12: <-- previous definition here`, 873 }, 874 }, 875 { 876 name: "nested duplicate", 877 input: ` 878 m { 879 nested: { 880 exists: true, 881 exists: true, 882 }, 883 } 884 `, 885 output: []interface{}{ 886 &struct { 887 Nested struct { 888 Exists bool 889 } 890 }{}, 891 }, 892 errors: []string{ 893 `<input>:5:13: property "nested.exists" already defined`, 894 `<input>:4:13: <-- previous definition here`, 895 }, 896 }, 897 { 898 name: "wrong type", 899 input: ` 900 m { 901 int: "foo", 902 } 903 `, 904 output: []interface{}{ 905 &struct { 906 Int *int64 907 }{}, 908 }, 909 errors: []string{ 910 `<input>:3:11: can't assign string value to int64 property "int"`, 911 }, 912 }, 913 { 914 name: "wrong type for map", 915 input: ` 916 m { 917 map: "foo", 918 } 919 `, 920 output: []interface{}{ 921 &struct { 922 Map struct { 923 S string 924 } 925 }{}, 926 }, 927 errors: []string{ 928 `<input>:3:11: can't assign string value to map property "map"`, 929 }, 930 }, 931 { 932 name: "wrong type for list", 933 input: ` 934 m { 935 list: "foo", 936 } 937 `, 938 output: []interface{}{ 939 &struct { 940 List []string 941 }{}, 942 }, 943 errors: []string{ 944 `<input>:3:12: can't assign string value to list property "list"`, 945 }, 946 }, 947 { 948 name: "wrong type for list of maps", 949 input: ` 950 m { 951 map_list: "foo", 952 } 953 `, 954 output: []interface{}{ 955 &struct { 956 Map_list []struct { 957 S string 958 } 959 }{}, 960 }, 961 errors: []string{ 962 `<input>:3:16: can't assign string value to list property "map_list"`, 963 }, 964 }, 965 } 966 967 for _, testCase := range testCases { 968 t.Run(testCase.name, func(t *testing.T) { 969 r := bytes.NewBufferString(testCase.input) 970 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil)) 971 if len(errs) != 0 { 972 t.Errorf("test case: %s", testCase.input) 973 t.Errorf("unexpected parse errors:") 974 for _, err := range errs { 975 t.Errorf(" %s", err) 976 } 977 t.FailNow() 978 } 979 980 for _, def := range file.Defs { 981 module, ok := def.(*parser.Module) 982 if !ok { 983 continue 984 } 985 986 var output []interface{} 987 for _, p := range testCase.output { 988 output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface()) 989 } 990 991 _, errs = UnpackProperties(module.Properties, output...) 992 993 printErrors := false 994 for _, expectedErr := range testCase.errors { 995 foundError := false 996 for _, err := range errs { 997 if err.Error() == expectedErr { 998 foundError = true 999 } 1000 } 1001 if !foundError { 1002 t.Errorf("expected error %s", expectedErr) 1003 printErrors = true 1004 } 1005 } 1006 if printErrors { 1007 t.Errorf("got errors:") 1008 for _, err := range errs { 1009 t.Errorf(" %s", err.Error()) 1010 } 1011 } 1012 } 1013 }) 1014 } 1015} 1016 1017func BenchmarkUnpackProperties(b *testing.B) { 1018 run := func(b *testing.B, props []interface{}, input string) { 1019 b.ReportAllocs() 1020 b.StopTimer() 1021 r := bytes.NewBufferString(input) 1022 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil)) 1023 if len(errs) != 0 { 1024 b.Errorf("test case: %s", input) 1025 b.Errorf("unexpected parse errors:") 1026 for _, err := range errs { 1027 b.Errorf(" %s", err) 1028 } 1029 b.FailNow() 1030 } 1031 1032 for i := 0; i < b.N; i++ { 1033 for _, def := range file.Defs { 1034 module, ok := def.(*parser.Module) 1035 if !ok { 1036 continue 1037 } 1038 1039 var output []interface{} 1040 for _, p := range props { 1041 output = append(output, CloneProperties(reflect.ValueOf(p)).Interface()) 1042 } 1043 1044 b.StartTimer() 1045 _, errs = UnpackProperties(module.Properties, output...) 1046 b.StopTimer() 1047 if len(errs) > 0 { 1048 b.Errorf("unexpected unpack errors:") 1049 for _, err := range errs { 1050 b.Errorf(" %s", err) 1051 } 1052 } 1053 } 1054 } 1055 } 1056 1057 b.Run("basic", func(b *testing.B) { 1058 props := []interface{}{ 1059 &struct { 1060 Nested struct { 1061 S string 1062 } 1063 }{}, 1064 } 1065 bp := ` 1066 m { 1067 nested: { 1068 s: "abc", 1069 }, 1070 } 1071 ` 1072 run(b, props, bp) 1073 }) 1074 1075 b.Run("interface", func(b *testing.B) { 1076 props := []interface{}{ 1077 &struct { 1078 Nested interface{} 1079 }{ 1080 Nested: (*struct { 1081 S string 1082 })(nil), 1083 }, 1084 } 1085 bp := ` 1086 m { 1087 nested: { 1088 s: "abc", 1089 }, 1090 } 1091 ` 1092 run(b, props, bp) 1093 }) 1094 1095 b.Run("many", func(b *testing.B) { 1096 props := []interface{}{ 1097 &struct { 1098 A *string 1099 B *string 1100 C *string 1101 D *string 1102 E *string 1103 F *string 1104 G *string 1105 H *string 1106 I *string 1107 J *string 1108 }{}, 1109 } 1110 bp := ` 1111 m { 1112 a: "a", 1113 b: "b", 1114 c: "c", 1115 d: "d", 1116 e: "e", 1117 f: "f", 1118 g: "g", 1119 h: "h", 1120 i: "i", 1121 j: "j", 1122 } 1123 ` 1124 run(b, props, bp) 1125 }) 1126 1127 b.Run("deep", func(b *testing.B) { 1128 props := []interface{}{ 1129 &struct { 1130 Nested struct { 1131 Nested struct { 1132 Nested struct { 1133 Nested struct { 1134 Nested struct { 1135 Nested struct { 1136 Nested struct { 1137 Nested struct { 1138 Nested struct { 1139 Nested struct { 1140 S string 1141 } 1142 } 1143 } 1144 } 1145 } 1146 } 1147 } 1148 } 1149 } 1150 } 1151 }{}, 1152 } 1153 bp := ` 1154 m { 1155 nested: { nested: { nested: { nested: { nested: { 1156 nested: { nested: { nested: { nested: { nested: { 1157 s: "abc", 1158 }, }, }, }, }, 1159 }, }, }, }, }, 1160 } 1161 ` 1162 run(b, props, bp) 1163 }) 1164 1165 b.Run("mix", func(b *testing.B) { 1166 props := []interface{}{ 1167 &struct { 1168 Name string 1169 Flag bool 1170 Settings []string 1171 Perarch *struct { 1172 Arm string 1173 Arm64 string 1174 } 1175 Configvars []struct { 1176 Name string 1177 Values []string 1178 } 1179 }{}, 1180 } 1181 bp := ` 1182 m { 1183 name: "mymodule", 1184 flag: true, 1185 settings: ["foo1", "foo2", "foo3",], 1186 perarch: { 1187 arm: "32", 1188 arm64: "64", 1189 }, 1190 configvars: [ 1191 { name: "var1", values: ["var1:1", "var1:2", ], }, 1192 { name: "var2", values: ["var2:1", "var2:2", ], }, 1193 ], 1194 } 1195 ` 1196 run(b, props, bp) 1197 }) 1198} 1199