1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2024 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage proptools 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "regexp" 19*1fa6dee9SAndroid Build Coastguard Worker "strings" 20*1fa6dee9SAndroid Build Coastguard Worker "testing" 21*1fa6dee9SAndroid Build Coastguard Worker 22*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/parser" 23*1fa6dee9SAndroid Build Coastguard Worker) 24*1fa6dee9SAndroid Build Coastguard Worker 25*1fa6dee9SAndroid Build Coastguard Workertype testSymlinkStruct struct { 26*1fa6dee9SAndroid Build Coastguard Worker Target string 27*1fa6dee9SAndroid Build Coastguard Worker Name string 28*1fa6dee9SAndroid Build Coastguard Worker} 29*1fa6dee9SAndroid Build Coastguard Worker 30*1fa6dee9SAndroid Build Coastguard Workertype testPropStructNested struct { 31*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr *string 32*1fa6dee9SAndroid Build Coastguard Worker} 33*1fa6dee9SAndroid Build Coastguard Worker 34*1fa6dee9SAndroid Build Coastguard Workertype testPropStruct struct { 35*1fa6dee9SAndroid Build Coastguard Worker My_string string 36*1fa6dee9SAndroid Build Coastguard Worker My_configurable_string Configurable[string] 37*1fa6dee9SAndroid Build Coastguard Worker My_configurable_string_list Configurable[[]string] 38*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr *string 39*1fa6dee9SAndroid Build Coastguard Worker My_string_list []string 40*1fa6dee9SAndroid Build Coastguard Worker My_struct_list []testSymlinkStruct 41*1fa6dee9SAndroid Build Coastguard Worker My_bool bool 42*1fa6dee9SAndroid Build Coastguard Worker My_int int 43*1fa6dee9SAndroid Build Coastguard Worker My_int64 int64 44*1fa6dee9SAndroid Build Coastguard Worker Nested testPropStructNested 45*1fa6dee9SAndroid Build Coastguard Worker} 46*1fa6dee9SAndroid Build Coastguard Worker 47*1fa6dee9SAndroid Build Coastguard Workertype testPropStructOnlyConfigurableStringList struct { 48*1fa6dee9SAndroid Build Coastguard Worker My_configurable_string_list Configurable[[]string] 49*1fa6dee9SAndroid Build Coastguard Worker} 50*1fa6dee9SAndroid Build Coastguard Worker 51*1fa6dee9SAndroid Build Coastguard Workerfunc TestRepack(t *testing.T) { 52*1fa6dee9SAndroid Build Coastguard Worker testCases := []struct { 53*1fa6dee9SAndroid Build Coastguard Worker name string 54*1fa6dee9SAndroid Build Coastguard Worker propStructs []interface{} 55*1fa6dee9SAndroid Build Coastguard Worker expectedBp string 56*1fa6dee9SAndroid Build Coastguard Worker expectedErr string 57*1fa6dee9SAndroid Build Coastguard Worker }{ 58*1fa6dee9SAndroid Build Coastguard Worker { 59*1fa6dee9SAndroid Build Coastguard Worker name: "Simple prop struct", 60*1fa6dee9SAndroid Build Coastguard Worker propStructs: []interface{}{&testPropStruct{ 61*1fa6dee9SAndroid Build Coastguard Worker My_string: "foo", 62*1fa6dee9SAndroid Build Coastguard Worker My_configurable_string: NewSimpleConfigurable("qux"), 63*1fa6dee9SAndroid Build Coastguard Worker My_configurable_string_list: NewSimpleConfigurable([]string{"a", "b", "c"}), 64*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr: StringPtr("bar"), 65*1fa6dee9SAndroid Build Coastguard Worker My_string_list: []string{"foo", "bar"}, 66*1fa6dee9SAndroid Build Coastguard Worker My_struct_list: []testSymlinkStruct{ 67*1fa6dee9SAndroid Build Coastguard Worker {Name: "foo", Target: "foo_target"}, 68*1fa6dee9SAndroid Build Coastguard Worker {Name: "bar", Target: "bar_target"}, 69*1fa6dee9SAndroid Build Coastguard Worker }, 70*1fa6dee9SAndroid Build Coastguard Worker My_bool: true, 71*1fa6dee9SAndroid Build Coastguard Worker My_int: 5, 72*1fa6dee9SAndroid Build Coastguard Worker My_int64: 64, 73*1fa6dee9SAndroid Build Coastguard Worker Nested: testPropStructNested{ 74*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr: StringPtr("baz"), 75*1fa6dee9SAndroid Build Coastguard Worker }, 76*1fa6dee9SAndroid Build Coastguard Worker }}, 77*1fa6dee9SAndroid Build Coastguard Worker expectedBp: ` 78*1fa6dee9SAndroid Build Coastguard Workermodule { 79*1fa6dee9SAndroid Build Coastguard Worker my_string: "foo", 80*1fa6dee9SAndroid Build Coastguard Worker my_configurable_string: "qux", 81*1fa6dee9SAndroid Build Coastguard Worker my_configurable_string_list: [ 82*1fa6dee9SAndroid Build Coastguard Worker "a", 83*1fa6dee9SAndroid Build Coastguard Worker "b", 84*1fa6dee9SAndroid Build Coastguard Worker "c", 85*1fa6dee9SAndroid Build Coastguard Worker ], 86*1fa6dee9SAndroid Build Coastguard Worker my_string_ptr: "bar", 87*1fa6dee9SAndroid Build Coastguard Worker my_string_list: [ 88*1fa6dee9SAndroid Build Coastguard Worker "foo", 89*1fa6dee9SAndroid Build Coastguard Worker "bar", 90*1fa6dee9SAndroid Build Coastguard Worker ], 91*1fa6dee9SAndroid Build Coastguard Worker my_struct_list: [ 92*1fa6dee9SAndroid Build Coastguard Worker { 93*1fa6dee9SAndroid Build Coastguard Worker Target: "foo_target", 94*1fa6dee9SAndroid Build Coastguard Worker Name: "foo", 95*1fa6dee9SAndroid Build Coastguard Worker }, 96*1fa6dee9SAndroid Build Coastguard Worker { 97*1fa6dee9SAndroid Build Coastguard Worker Target: "bar_target", 98*1fa6dee9SAndroid Build Coastguard Worker Name: "bar", 99*1fa6dee9SAndroid Build Coastguard Worker }, 100*1fa6dee9SAndroid Build Coastguard Worker ], 101*1fa6dee9SAndroid Build Coastguard Worker my_bool: true, 102*1fa6dee9SAndroid Build Coastguard Worker my_int: 5, 103*1fa6dee9SAndroid Build Coastguard Worker my_int64: 64, 104*1fa6dee9SAndroid Build Coastguard Worker nested: { 105*1fa6dee9SAndroid Build Coastguard Worker my_string_ptr: "baz", 106*1fa6dee9SAndroid Build Coastguard Worker }, 107*1fa6dee9SAndroid Build Coastguard Worker}`, 108*1fa6dee9SAndroid Build Coastguard Worker }, 109*1fa6dee9SAndroid Build Coastguard Worker { 110*1fa6dee9SAndroid Build Coastguard Worker name: "Complicated select", 111*1fa6dee9SAndroid Build Coastguard Worker propStructs: []interface{}{&testPropStructOnlyConfigurableStringList{ 112*1fa6dee9SAndroid Build Coastguard Worker My_configurable_string_list: createComplicatedSelect(), 113*1fa6dee9SAndroid Build Coastguard Worker }}, 114*1fa6dee9SAndroid Build Coastguard Worker expectedBp: ` 115*1fa6dee9SAndroid Build Coastguard Workermodule { 116*1fa6dee9SAndroid Build Coastguard Worker my_configurable_string_list: ["a"] + select((os(), arch()), { 117*1fa6dee9SAndroid Build Coastguard Worker ("android", "x86"): [ 118*1fa6dee9SAndroid Build Coastguard Worker "android", 119*1fa6dee9SAndroid Build Coastguard Worker "x86", 120*1fa6dee9SAndroid Build Coastguard Worker ], 121*1fa6dee9SAndroid Build Coastguard Worker ("android", "arm64"): [ 122*1fa6dee9SAndroid Build Coastguard Worker "android", 123*1fa6dee9SAndroid Build Coastguard Worker "arm64", 124*1fa6dee9SAndroid Build Coastguard Worker ], 125*1fa6dee9SAndroid Build Coastguard Worker (default, "x86"): [ 126*1fa6dee9SAndroid Build Coastguard Worker "default", 127*1fa6dee9SAndroid Build Coastguard Worker "x86", 128*1fa6dee9SAndroid Build Coastguard Worker ], 129*1fa6dee9SAndroid Build Coastguard Worker (default, default): [ 130*1fa6dee9SAndroid Build Coastguard Worker "default", 131*1fa6dee9SAndroid Build Coastguard Worker "default", 132*1fa6dee9SAndroid Build Coastguard Worker ], 133*1fa6dee9SAndroid Build Coastguard Worker }) + ["b"], 134*1fa6dee9SAndroid Build Coastguard Worker}`, 135*1fa6dee9SAndroid Build Coastguard Worker }, 136*1fa6dee9SAndroid Build Coastguard Worker { 137*1fa6dee9SAndroid Build Coastguard Worker name: "Multiple property structs", 138*1fa6dee9SAndroid Build Coastguard Worker propStructs: []interface{}{ 139*1fa6dee9SAndroid Build Coastguard Worker &testPropStruct{ 140*1fa6dee9SAndroid Build Coastguard Worker My_string: "foo", 141*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr: nil, 142*1fa6dee9SAndroid Build Coastguard Worker My_string_list: []string{"foo", "bar"}, 143*1fa6dee9SAndroid Build Coastguard Worker My_bool: true, 144*1fa6dee9SAndroid Build Coastguard Worker My_int: 5, 145*1fa6dee9SAndroid Build Coastguard Worker }, 146*1fa6dee9SAndroid Build Coastguard Worker &testPropStructNested{ 147*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr: StringPtr("bar"), 148*1fa6dee9SAndroid Build Coastguard Worker }, 149*1fa6dee9SAndroid Build Coastguard Worker }, 150*1fa6dee9SAndroid Build Coastguard Worker expectedBp: ` 151*1fa6dee9SAndroid Build Coastguard Workermodule { 152*1fa6dee9SAndroid Build Coastguard Worker my_string: "foo", 153*1fa6dee9SAndroid Build Coastguard Worker my_string_ptr: "bar", 154*1fa6dee9SAndroid Build Coastguard Worker my_string_list: [ 155*1fa6dee9SAndroid Build Coastguard Worker "foo", 156*1fa6dee9SAndroid Build Coastguard Worker "bar", 157*1fa6dee9SAndroid Build Coastguard Worker ], 158*1fa6dee9SAndroid Build Coastguard Worker my_struct_list: [], 159*1fa6dee9SAndroid Build Coastguard Worker my_bool: true, 160*1fa6dee9SAndroid Build Coastguard Worker my_int: 5, 161*1fa6dee9SAndroid Build Coastguard Worker my_int64: 0, 162*1fa6dee9SAndroid Build Coastguard Worker}`, 163*1fa6dee9SAndroid Build Coastguard Worker }, 164*1fa6dee9SAndroid Build Coastguard Worker { 165*1fa6dee9SAndroid Build Coastguard Worker name: "Multiple conflicting property structs", 166*1fa6dee9SAndroid Build Coastguard Worker propStructs: []interface{}{ 167*1fa6dee9SAndroid Build Coastguard Worker &testPropStruct{ 168*1fa6dee9SAndroid Build Coastguard Worker My_string: "foo", 169*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr: StringPtr("foo"), 170*1fa6dee9SAndroid Build Coastguard Worker My_string_list: []string{"foo", "bar"}, 171*1fa6dee9SAndroid Build Coastguard Worker My_bool: true, 172*1fa6dee9SAndroid Build Coastguard Worker My_int: 5, 173*1fa6dee9SAndroid Build Coastguard Worker }, 174*1fa6dee9SAndroid Build Coastguard Worker &testPropStructNested{ 175*1fa6dee9SAndroid Build Coastguard Worker My_string_ptr: StringPtr("bar"), 176*1fa6dee9SAndroid Build Coastguard Worker }, 177*1fa6dee9SAndroid Build Coastguard Worker }, 178*1fa6dee9SAndroid Build Coastguard Worker expectedErr: `Conflicting fields in property structs had values "foo" and "bar"`, 179*1fa6dee9SAndroid Build Coastguard Worker }, 180*1fa6dee9SAndroid Build Coastguard Worker } 181*1fa6dee9SAndroid Build Coastguard Worker 182*1fa6dee9SAndroid Build Coastguard Worker for _, tc := range testCases { 183*1fa6dee9SAndroid Build Coastguard Worker t.Run(tc.name, func(t *testing.T) { 184*1fa6dee9SAndroid Build Coastguard Worker result, err := RepackProperties(tc.propStructs) 185*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 186*1fa6dee9SAndroid Build Coastguard Worker if tc.expectedErr != "" { 187*1fa6dee9SAndroid Build Coastguard Worker match, err2 := regexp.MatchString(tc.expectedErr, err.Error()) 188*1fa6dee9SAndroid Build Coastguard Worker if err2 != nil { 189*1fa6dee9SAndroid Build Coastguard Worker t.Fatal(err2) 190*1fa6dee9SAndroid Build Coastguard Worker } 191*1fa6dee9SAndroid Build Coastguard Worker if !match { 192*1fa6dee9SAndroid Build Coastguard Worker t.Fatalf("Expected error matching %q, found %q", tc.expectedErr, err.Error()) 193*1fa6dee9SAndroid Build Coastguard Worker } 194*1fa6dee9SAndroid Build Coastguard Worker return 195*1fa6dee9SAndroid Build Coastguard Worker } else { 196*1fa6dee9SAndroid Build Coastguard Worker t.Fatal(err) 197*1fa6dee9SAndroid Build Coastguard Worker } 198*1fa6dee9SAndroid Build Coastguard Worker } else if tc.expectedErr != "" { 199*1fa6dee9SAndroid Build Coastguard Worker t.Fatalf("Expected error matching %q, but got success", tc.expectedErr) 200*1fa6dee9SAndroid Build Coastguard Worker } 201*1fa6dee9SAndroid Build Coastguard Worker file := &parser.File{ 202*1fa6dee9SAndroid Build Coastguard Worker Defs: []parser.Definition{ 203*1fa6dee9SAndroid Build Coastguard Worker &parser.Module{ 204*1fa6dee9SAndroid Build Coastguard Worker Type: "module", 205*1fa6dee9SAndroid Build Coastguard Worker Map: *result, 206*1fa6dee9SAndroid Build Coastguard Worker }, 207*1fa6dee9SAndroid Build Coastguard Worker }, 208*1fa6dee9SAndroid Build Coastguard Worker } 209*1fa6dee9SAndroid Build Coastguard Worker bytes, err := parser.Print(file) 210*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 211*1fa6dee9SAndroid Build Coastguard Worker t.Fatal(err) 212*1fa6dee9SAndroid Build Coastguard Worker } 213*1fa6dee9SAndroid Build Coastguard Worker expected := strings.TrimSpace(tc.expectedBp) 214*1fa6dee9SAndroid Build Coastguard Worker actual := strings.TrimSpace(string(bytes)) 215*1fa6dee9SAndroid Build Coastguard Worker if expected != actual { 216*1fa6dee9SAndroid Build Coastguard Worker t.Fatalf("Expected:\n%s\nBut found:\n%s\n", expected, actual) 217*1fa6dee9SAndroid Build Coastguard Worker } 218*1fa6dee9SAndroid Build Coastguard Worker }) 219*1fa6dee9SAndroid Build Coastguard Worker } 220*1fa6dee9SAndroid Build Coastguard Worker} 221*1fa6dee9SAndroid Build Coastguard Worker 222*1fa6dee9SAndroid Build Coastguard Workerfunc createComplicatedSelect() Configurable[[]string] { 223*1fa6dee9SAndroid Build Coastguard Worker result := NewSimpleConfigurable([]string{"a"}) 224*1fa6dee9SAndroid Build Coastguard Worker result.Append(NewConfigurable([]ConfigurableCondition{ 225*1fa6dee9SAndroid Build Coastguard Worker NewConfigurableCondition("os", nil), 226*1fa6dee9SAndroid Build Coastguard Worker NewConfigurableCondition("arch", nil), 227*1fa6dee9SAndroid Build Coastguard Worker }, []ConfigurableCase[[]string]{ 228*1fa6dee9SAndroid Build Coastguard Worker NewConfigurableCase([]ConfigurablePattern{ 229*1fa6dee9SAndroid Build Coastguard Worker NewStringConfigurablePattern("android"), 230*1fa6dee9SAndroid Build Coastguard Worker NewStringConfigurablePattern("x86"), 231*1fa6dee9SAndroid Build Coastguard Worker }, &[]string{"android", "x86"}), 232*1fa6dee9SAndroid Build Coastguard Worker NewConfigurableCase([]ConfigurablePattern{ 233*1fa6dee9SAndroid Build Coastguard Worker NewStringConfigurablePattern("android"), 234*1fa6dee9SAndroid Build Coastguard Worker NewStringConfigurablePattern("arm64"), 235*1fa6dee9SAndroid Build Coastguard Worker }, &[]string{"android", "arm64"}), 236*1fa6dee9SAndroid Build Coastguard Worker NewConfigurableCase([]ConfigurablePattern{ 237*1fa6dee9SAndroid Build Coastguard Worker NewDefaultConfigurablePattern(), 238*1fa6dee9SAndroid Build Coastguard Worker NewStringConfigurablePattern("x86"), 239*1fa6dee9SAndroid Build Coastguard Worker }, &[]string{"default", "x86"}), 240*1fa6dee9SAndroid Build Coastguard Worker NewConfigurableCase([]ConfigurablePattern{ 241*1fa6dee9SAndroid Build Coastguard Worker NewDefaultConfigurablePattern(), 242*1fa6dee9SAndroid Build Coastguard Worker NewDefaultConfigurablePattern(), 243*1fa6dee9SAndroid Build Coastguard Worker }, &[]string{"default", "default"}), 244*1fa6dee9SAndroid Build Coastguard Worker })) 245*1fa6dee9SAndroid Build Coastguard Worker result.Append(NewSimpleConfigurable([]string{"b"})) 246*1fa6dee9SAndroid Build Coastguard Worker return result 247*1fa6dee9SAndroid Build Coastguard Worker} 248