1// Copyright 2020 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 main 16 17import ( 18 "strings" 19 "testing" 20 21 "github.com/google/blueprint/parser" 22 "github.com/google/blueprint/proptools" 23) 24 25var testCases = []struct { 26 name string 27 input string 28 output string 29 property string 30 addSet string 31 removeSet string 32 setString *string 33}{ 34 { 35 name: "add", 36 input: ` 37 cc_foo { 38 name: "foo", 39 } 40 `, 41 output: ` 42 cc_foo { 43 name: "foo", 44 deps: ["bar"], 45 } 46 `, 47 property: "deps", 48 addSet: "bar", 49 }, 50 { 51 name: "remove", 52 input: ` 53 cc_foo { 54 name: "foo", 55 deps: ["bar"], 56 } 57 `, 58 output: ` 59 cc_foo { 60 name: "foo", 61 deps: [], 62 } 63 `, 64 property: "deps", 65 removeSet: "bar", 66 }, 67 { 68 name: "nested add", 69 input: ` 70 cc_foo { 71 name: "foo", 72 } 73 `, 74 output: ` 75 cc_foo { 76 name: "foo", 77 arch: { 78 arm: { 79 deps: [ 80 "dep2", 81 "nested_dep",], 82 }, 83 }, 84 } 85 `, 86 property: "arch.arm.deps", 87 addSet: "nested_dep,dep2", 88 }, 89 { 90 name: "nested remove", 91 input: ` 92 cc_foo { 93 name: "foo", 94 arch: { 95 arm: { 96 deps: [ 97 "dep2", 98 "nested_dep", 99 ], 100 }, 101 }, 102 } 103 `, 104 output: ` 105 cc_foo { 106 name: "foo", 107 arch: { 108 arm: { 109 deps: [ 110 ], 111 }, 112 }, 113 } 114 `, 115 property: "arch.arm.deps", 116 removeSet: "nested_dep,dep2", 117 }, 118 { 119 name: "add existing", 120 input: ` 121 cc_foo { 122 name: "foo", 123 arch: { 124 arm: { 125 deps: [ 126 "nested_dep", 127 "dep2", 128 ], 129 }, 130 }, 131 } 132 `, 133 output: ` 134 cc_foo { 135 name: "foo", 136 arch: { 137 arm: { 138 deps: [ 139 "nested_dep", 140 "dep2", 141 ], 142 }, 143 }, 144 } 145 `, 146 property: "arch.arm.deps", 147 addSet: "dep2,dep2", 148 }, 149 { 150 name: "remove missing", 151 input: ` 152 cc_foo { 153 name: "foo", 154 arch: { 155 arm: { 156 deps: [ 157 "nested_dep", 158 "dep2", 159 ], 160 }, 161 }, 162 } 163 `, 164 output: ` 165 cc_foo { 166 name: "foo", 167 arch: { 168 arm: { 169 deps: [ 170 "nested_dep", 171 "dep2", 172 ], 173 }, 174 }, 175 } 176 `, 177 property: "arch.arm.deps", 178 removeSet: "dep3,dep4", 179 }, 180 { 181 name: "remove non existent", 182 input: ` 183 cc_foo { 184 name: "foo", 185 } 186 `, 187 output: ` 188 cc_foo { 189 name: "foo", 190 } 191 `, 192 property: "deps", 193 removeSet: "bar", 194 }, 195 { 196 name: "remove non existent nested", 197 input: ` 198 cc_foo { 199 name: "foo", 200 arch: {}, 201 } 202 `, 203 output: ` 204 cc_foo { 205 name: "foo", 206 arch: {}, 207 } 208 `, 209 property: "arch.arm.deps", 210 removeSet: "dep3,dep4", 211 }, 212 { 213 name: "add numeric sorted", 214 input: ` 215 cc_foo { 216 name: "foo", 217 versions: ["1", "2"], 218 } 219 `, 220 output: ` 221 cc_foo { 222 name: "foo", 223 versions: [ 224 "1", 225 "2", 226 "10", 227 ], 228 } 229 `, 230 property: "versions", 231 addSet: "10", 232 }, 233 { 234 name: "add mixed sorted", 235 input: ` 236 cc_foo { 237 name: "foo", 238 deps: ["bar-v1-bar", "bar-v2-bar"], 239 } 240 `, 241 output: ` 242 cc_foo { 243 name: "foo", 244 deps: [ 245 "bar-v1-bar", 246 "bar-v2-bar", 247 "bar-v10-bar", 248 ], 249 } 250 `, 251 property: "deps", 252 addSet: "bar-v10-bar", 253 }, 254 { 255 name: "set string", 256 input: ` 257 cc_foo { 258 name: "foo", 259 } 260 `, 261 output: ` 262 cc_foo { 263 name: "foo", 264 foo: "bar", 265 } 266 `, 267 property: "foo", 268 setString: proptools.StringPtr("bar"), 269 }, 270 { 271 name: "set existing string", 272 input: ` 273 cc_foo { 274 name: "foo", 275 foo: "baz", 276 } 277 `, 278 output: ` 279 cc_foo { 280 name: "foo", 281 foo: "bar", 282 } 283 `, 284 property: "foo", 285 setString: proptools.StringPtr("bar"), 286 }, 287} 288 289func simplifyModuleDefinition(def string) string { 290 var result string 291 for _, line := range strings.Split(def, "\n") { 292 result += strings.TrimSpace(line) 293 } 294 return result 295} 296 297func TestProcessModule(t *testing.T) { 298 for i, testCase := range testCases { 299 t.Run(testCase.name, func(t *testing.T) { 300 targetedProperty.Set(testCase.property) 301 addIdents.Set(testCase.addSet) 302 removeIdents.Set(testCase.removeSet) 303 setString = testCase.setString 304 305 inAst, errs := parser.ParseAndEval("", strings.NewReader(testCase.input), parser.NewScope(nil)) 306 if len(errs) > 0 { 307 for _, err := range errs { 308 t.Errorf(" %s", err) 309 } 310 t.Errorf("failed to parse:") 311 t.Errorf("%+v", testCase) 312 t.FailNow() 313 } 314 315 if inModule, ok := inAst.Defs[0].(*parser.Module); !ok { 316 t.Fatalf(" input must only contain a single module definition: %s", testCase.input) 317 } else { 318 _, errs := processModule(inModule, "", inAst) 319 if len(errs) > 0 { 320 t.Errorf("test case %d:", i) 321 for _, err := range errs { 322 t.Errorf(" %s", err) 323 } 324 } 325 inModuleText, _ := parser.Print(inAst) 326 inModuleString := string(inModuleText) 327 if simplifyModuleDefinition(inModuleString) != simplifyModuleDefinition(testCase.output) { 328 t.Errorf("test case %d:", i) 329 t.Errorf("expected module definition:") 330 t.Errorf(" %s", testCase.output) 331 t.Errorf("actual module definition:") 332 t.Errorf(" %s", inModuleString) 333 } 334 } 335 }) 336 } 337 338} 339